2010-09-12 8 views
42

J'ai essayé de lire divers articles de blog qui tentent d'expliquer alias_method_chain et les raisons de l'utiliser et de ne pas l'utiliser. En particulier, je me suis attentif à:Ruby on Rails: alias_method_chain, que fait-il exactement?

http://weblog.rubyonrails.org/2006/4/26/new-in-rails-module-alias_method_chain

et

http://yehudakatz.com/2009/03/06/alias_method_chain-in-models/

je ne vois pas encore une utilité pratique pour alias_method_chain. Quelqu'un pourrait-il expliquer quelques choses?

1 - est-il toujours utilisé?
2 - Quand utiliseriez-vous alias_method_chain et pourquoi?

Répondre

90

1 - est-il toujours utilisé?

Apparemment oui, alias_method_chain() est still used in Rails (de la version 3.0.0).

2 - Quand utiliseriez-vous alias_method_chain et pourquoi?

(Note:. ce qui suit est en grande partie basée sur la discussion de alias_method_chain() en Metaprogramming Ruby par Paolo Perrotta, qui est un excellent livre que vous devriez obtenir vos mains sur)

Commençons par un exemple de base:

class Klass 
    def salute 
    puts "Aloha!" 
    end 
end 

Klass.new.salute # => Aloha! 

supposons maintenant que nous voulons entourer Klass#salute() avec le comportement de l'exploitation forestière. Nous pouvons faire ce que Perrotta appelle un alias autour:

class Klass 
    def salute_with_log 
    puts "Calling method..." 
    salute_without_log 
    puts "...Method called" 
    end 

    alias_method :salute_without_log, :salute 
    alias_method :salute, :salute_with_log 
end 

Klass.new.salute 
# Prints the following: 
# Calling method... 
# Aloha! 
# ...Method called 

Nous avons défini une nouvelle méthode appelée salute_with_log() et à salute() un alias. Le code qui appelait salute() fonctionne toujours, mais il obtient également le nouveau comportement de journalisation.Nous avons également défini un alias à l'salute() d'origine, afin que nous puissions saluer encore sans vous connecter:

Klass.new.salute_without_log # => Aloha! 

Ainsi, salute() est maintenant appelé salute_without_log(). Si nous voulons la journalisation, nous pouvons appeler salute_with_log() ou salute(), qui sont des alias de la même méthode. Confus? Bien!

Selon Perrotta, ce genre d'environ alias est très commun dans Rails:

un autre exemple de Rails résoudre un problème de sa propre manière. Il y a quelques versions , le code Rails contenait plusieurs instances du même idiome: un Autour Alias ​​ (155) a été utilisé pour ajouter une fonctionnalité à une méthode, et l'ancienne version de la méthode a été renommé quelque chose comme method_without_feature(). En dehors de les noms des méthodes qui ont changé chaque fois , le code qui a fait cela était toujours le même, dupliqués partout l'endroit. Dans la plupart des langues, ne peut pas éviter ce type de duplication. Dans Ruby, vous pouvez saupoudrer de magie de métaprogrammation sur votre modèle et l'extraire dans sa propre méthode ... et ainsi est né alias_method_chain().

En d'autres termes, vous fournir la méthode originale, foo(), et la méthode améliorée, foo_with_feature(), et vous vous retrouvez avec trois méthodes: foo(), foo_with_feature() et foo_without_feature(). Les deux premiers incluent la fonctionnalité, tandis que le troisième ne le fait pas. Au lieu de dupliquer ces alias tout autour, alias_method_chain() provided by ActiveSupport fait tous les alias pour vous.

+32

+1 pour dire "Confus? Bon!" – jperelli

+11

et petite addition: maintenant nous pouvons simplement taper '' 'alias_method_chain: foo,: feature''' et nous aurons 3 méthodes:' '' foo''', '' 'foo_with_feature''',' '' foo_without_feature '' 'qui sont correctement aliasés comme * Yases Sulaiman * décrivent avant – freemanoid

+2

" Toute technologie suffisamment avancée est indiscernable de la magie. " Arthur C. Clarke –

4

Je ne suis pas sûr que le Rails 3 soit sorti du style ou non, mais il est encore activement utilisé dans les versions antérieures.

Vous l'utilisez pour injecter des fonctionnalités avant (ou après) l'appel d'une méthode, sans modifier l'endroit qui appelle cette méthode. Voir cet exemple:

module SwitchableSmtp 
    module InstanceMethods 
    def deliver_with_switchable_smtp!(mail = @mail) 
     unless logger.nil? 
     logger.info "Switching SMTP server to: #{custom_smtp.inspect}" 
     end 
     ActionMailer::Base.smtp_settings = custom_smtp unless custom_smtp.nil? 
     deliver_without_switchable_smtp!(mail = @mail) 
    end 
    end 
    def self.included(receiver) 
    receiver.send :include, InstanceMethods 
    receiver.class_eval do 
     alias_method_chain :deliver!, :switchable_smtp 
    end 
    end 
end 

C'est un ajout à ActionMailer pour permettre la permutation sur les paramètres SMTP sur chaque appel à deliver!. En appelant alias_method_chain, vous êtes en mesure de définir une méthode deliver_with_switchable_smtp! dans laquelle vous faites vos trucs personnalisés, et appelez deliver_without_switchable_smtp! à partir de là lorsque vous avez terminé.

alias_method_chain alias l'ancien deliver! à votre nouvelle méthode personnalisée, de sorte que le reste de votre application ne sait même pas deliver! fait maintenant vos trucs sur commande aussi.

+0

Ne devrait pas 'alias_method_chain: livrer !,: switchable_smtp' être' alias_method_chain: livrer !,: deliver_with_switchable_smtp '! – Waseem

+0

Non, c'est vrai. – Waseem

2

est-il utilisé du tout?

Seems so. C'est une pratique courante chez les développeurs Rails

Quand utiliseriez-vous alias_method_chain et pourquoi?

Malgré les avertissements, alias_method_chain est toujours la principale stratégie utilisée lors de l'injection des fonctionnalités à une méthode existante, au moins était dans Rails 2.x et est suivi par de nombreuses personnes PROLONGER. Yehuda devrait enlever alias_method_chain des rails 3.0 pour dire de ses poteaux et commentaires dans des billets de Rails. Il est encore utilisé par de nombreuses extensions qui ajoutent un comportement personnalisé à certains points de l'exécution, tels que les enregistreurs, les reporters d'erreur, l'analyse comparative, l'injection de données, etc.

IMO, la meilleure alternative est d'inclure un module, ainsi vous avez décoration sur délégation. (Par exemple, suivez l'exemple 4 dans this post). De cette façon, vous pouvez modifier les objets même individuellement si vous le souhaitez, sans polluer les méthodes de la classe. L'inconvénient de ceci est que la chaîne de recherche de méthode augmente pour chaque module que vous injectez, mais c'est ce que les modules sont de toute façon.

question très intéressante, gardera un oeil sur ce que les autres pensent.