2010-07-03 5 views
17

La metaprogramación en ruby ​​es excelente porque la utilizo constantemente para emular la programación basada en prototipos y escribir rápidamente soluciones de prototipos a algunos problemas para probar su viabilidad. Así que me gustaría saber si hay alguna diferencia esencial entre los siguientes fragmentos de código:Métodos de singleton de Ruby con (class_eval, define_method) vs (example_eval, define_method)

(class << some_object; self; end).class_eval do 
    define_method(:method_name) do ... method body ... end 
end 

y

(class << some_object; self; end).instance_eval do 
    define_method(:method_name) do ... method body ... end 
end 

Ambas versiones del código define un método singleton y aún no han llegado contra todo lo que me ha obligado a elegir la combinación (instance_eval, define_method) sobre la combinación (class_eval, define_method) para definir un método singleton y me pregunto si hay alguna diferencia esencial entre los dos.

+1

Tenga en cuenta que la mejor manera de hacer lo anterior es simplemente 'define_singleton_method (: method_name) Do ... end' –

Respuesta

21

Sin diferencia para define_method. Pero hay una diferencia cuando usa def.

o = Object.new 

# class_eval example 
class << o; self; end.class_eval { def test1; :test1; end } 
o.test1 #=> test1 

# instance_eval example 
class << o; self; end.instance_eval { def test2; :test2; end } 
o.test2 #=> NoMethodError 

Por qué la diferencia de comportamiento entre def y define_method? define_method es una llamada a método y funciona en el self en el contexto eval. El self en ambos instance_eval y class_eval es el mismo - es el receptor (la clase de yo).

Sin embargo, def tiene un comportamiento diferente, no funciona en el self, sino en el default definee. En el caso de class_eval, default definee es lo mismo que self, pero para instance_eval es la metaclase de self.

¿Cómo accedemos al método test2 definido anteriormente? test2 debe ser un método de instancia definido en la metaclase de la clase de yo de e.

Es un método de clase en los eigenclass de O;

class << o; test2; end #=> :test2 
Cuestiones relacionadas