2010-09-12 21 views
42

He intentado leer varias publicaciones de blog que intentan explicar alias_method_chain y las razones para usarlo y no usarlo. En particular, yo hubiera seguido a:Ruby on Rails: alias_method_chain, ¿qué es exactamente?

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

y

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

todavía no ven ninguna utilidad práctica para alias_method_chain. ¿Alguien podría explicar algunas cosas?

1 - ¿Todavía se usa?
2 - ¿Cuándo utilizarías alias_method_chain y por qué?

Respuesta

90

1 - ¿Todavía se usa?

Al parecer sí, es alias_method_chain()still used in Rails (en la versión 3.0.0).

2 - ¿Cuándo utilizaría alias_method_chain y por qué?

(Nota:. el se basa en gran parte en la discusión de alias_method_chain() en Metaprogramming Ruby de Paolo Perrotta, que es un excelente libro que usted debe tener en sus manos después de)

Vamos a empezar con un ejemplo básico:

class Klass 
    def salute 
    puts "Aloha!" 
    end 
end 

Klass.new.salute # => Aloha! 

supongamos ahora que queremos rodear Klass#salute() con comportamiento de registro. Podemos hacer que lo que llama un Perrotta alrededor de alias:

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 

hemos definido un nuevo método llamado salute_with_log() y alias a salute(). El código que solía llamar a salute() todavía funciona, pero también obtiene el nuevo comportamiento de registro.También se define un alias a la original salute(), por lo que todavía podemos saludar sin registro:

Klass.new.salute_without_log # => Aloha! 

Así, salute() ahora se llama salute_without_log(). Si queremos iniciar sesión, podemos llamar al salute_with_log() o al salute(), que son alias del mismo método. ¿Confuso? ¡Bueno!

Según Perrotta, este tipo de alrededor de alias es muy común en los rieles:

ver otro ejemplo de rieles resolver un problema a su manera. Hace unos versiones, el código de Rails contenía muchas instancias del mismo lenguaje: una fue utilizado para añadir una característica a un método Alrededor Alias ​​ (155), y la vieja versión del método fue renombrado a algo así como method_without_feature(). Aparte de los nombres del método, que cambiaron cada vez, el código que hizo esto fue siempre el mismo, duplicado en el lugar. En la mayoría de los idiomas, no puede evitar ese tipo de duplicación. En Ruby, puede rociar un poco de magia de metaprogramación sobre su patrón y extraerlo en su propio método ... y así nació alias_method_chain().

En otras palabras, que proporcionan el método original, foo(), y el método mejorado, foo_with_feature(), y se termina con tres métodos: foo(), foo_with_feature() y foo_without_feature(). Los primeros dos incluyen la función, mientras que el tercero no. En lugar de duplicar estos alias por todos lados, alias_method_chain() provided by ActiveSupport hace todo el alias por usted.

+32

+1 por decir "¿Confundido? ¡Bien!" – jperelli

+11

y una pequeña adición: así que ahora podemos simplemente escribir '' 'alias_method_chain: foo,: feature''' y tendremos 3 métodos:' '' foo''', '' 'foo_with_feature''',' '' foo_without_feature '' 'que están correctamente alias como * Yases Sulaiman * describe antes de – freemanoid

+2

" Cualquier tecnología suficientemente avanzada es indistinguible de la magia ". Arthur C. Clarke –

4

No estoy seguro de si ha pasado de moda con Rails 3 o no, pero todavía se usa activamente en las versiones anteriores.

Se usa para inyectar algunas funciones antes (o después) de llamar a un método, sin modificar ningún lugar que llame a ese método. Vea este ejemplo:

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 

Eso es una adición a ActionMailer para permitir el intercambio de la configuración SMTP en cada llamada a deliver!. Al llamar al alias_method_chain, puede definir un método deliver_with_switchable_smtp! en el que puede hacer sus cosas personalizadas, y llamar al deliver_without_switchable_smtp! desde allí cuando haya terminado.

alias_method_chain alias el viejo deliver! a su nuevo método personalizado, por lo que el resto de su aplicación ni siquiera sabe deliver! ahora hace sus cosas encargo también.

+0

¿No debería 'alias_method_chain: entregar !,: switchable_smtp' ser' alias_method_chain: entregar !,: deliver_with_switchable_smtp '!? – Waseem

+0

No, eso es correcto. – Waseem

2

¿se usa en absoluto?

Seems so. Es una práctica común entre los desarrolladores de Rails

¿Cuándo utilizaría alias_method_chain y por qué?

pesar de las advertencias, alias_method_chain es todavía la principal estrategia utilizada cuando la inyección de funcionalidad a un método existente, por lo menos era en rieles 2.x y es seguido por muchas personas que se extienden ella. Yehuda debería eliminar alias_method_chain de rails 3.0 para que diga de sus publicaciones y comentarios en las entradas de Rails. Todavía es utilizado por muchas extensiones que agregan comportamiento personalizado en ciertos puntos de la ejecución, como registradores, reporteros de errores, evaluación comparativa, inyección de datos, etc.

IMO, la mejor alternativa es incluir un módulo, por lo que tiene decoración sobre la delegación. (Por ejemplo, siga el ejemplo 4 en this post). De esta forma, puede modificar los objetos incluso individualmente si lo desea, sin contaminar los métodos de la clase. La desventaja de esto es que la cadena de búsqueda de métodos aumenta para cada módulo que se inyecta, pero de todos modos es de lo que se trata los módulos.

Pregunta muy interesante, eche un vistazo a lo que otras personas piensan al respecto.