2010-12-10 12 views
26

estoy leyendo la sección de Metaprogramación de programación Ruby 1.9 y estoy teniendo problemas para entender lo que está pasando internamente entre class_eval/class_exec vs instance_eval/instance_exec.de Ruby definición y instance_eval vs class_eval

Así que en primer lugar, mi opinión es que def añade un método para la tabla de métodos de self (la clase de objeto):

class A 
    puts self # => A 
    def foo; 42; end # added to the method table of self, so becomes an instance method 
end 
A.new.foo # => 42 

Y si usamos class_eval, obtenemos el mismo comportamiento:

A.class_eval do 
    puts self # => A 
    def bar; 42; end # same as above 
end 
A.new.bar # => 42 

Pero de alguna manera en el caso instance_eval, las cosas son diferentes:

A.instance_eval do 
    puts self # => A 
    def baz; 42; end # added to the method table of an anonymous 
        # singleton class of self, so becomes a class method 
end 
puts A.baz # => 42 

s = 'string' 
s.instance_eval do ... end # same behavior, so now def creates an instance method 

Así que entiendo la diferencia funcional entre class_eval y instance_eval.

Pero los contextos dentro de los bloques class_eval y instance_eval vistazo exactamente lo mismo para mí - en particular, self puntos para el mismo objeto, y el local_variables son los mismos. Entonces, ¿qué está pasando dentro de los bloques (internamente) que está haciendo que def actúe diferente?

¿Hay alguna documentación que pueda leer? El RDoc para instance_eval y class_eval no ayuda. Al mirar la fuente, instance_eval parece configurar un objeto de clase singleton, mientras que class_eval no lo hace, pero ¿esta diferencia es visible fuera del código C, en el nivel de Ruby?

Respuesta

31

Creo que su confusión proviene del hecho de que def no depende del yo actual, podría pensar que es una "clase actual" que tiene sus propias reglas.

Siguiendo sus ejemplos:

class A 
    # defs here go to A 
    puts self # => A 
    class << self 
    #defs here go to A's eigenclass 
    end 
end 

A.class_eval do 
    #defs here go to A 
end 

A.instance_eval do 
    #defs here go to A's eigenclass  
end 

s = "Hello World" 

class << s 
    #defs here go to s's eigenclass 
end 

Aquí está la parte del capítulo que habla sobre el tema y que está bastante claro sobre el comportamiento

class_eval y instance_eval tanto SET auto durante la duración de el bloque. Sin embargo, difieren en la forma en que configuraron el entorno para la definición del método . class_eval prepara las cosas como si estuviera en el cuerpo de una definición de clase , por lo definiciones de métodos serán definir los métodos de instancia por el contrario, llamando instance_eval en una clase actúa como si estuviera trabajando dentro de la clase Singleton de sí mismo. Por lo tanto, los métodos que defina se convertirán en métodos de clase.

Lo único que creo que vale la pena agregar es que puede llamar a instance_eval en cualquier objeto, no solo en clases, y el comportamiento no cambia, pero tiene diferentes consecuencias.

leer un poco relevantes:

Ruby: instance_eval and class_eval method definitions

Chapter 4 of this most excelent series

+0

Hm, ya veo, eso tiene sentido. ¿Hay alguna manera de inspeccionar esa "clase actual" en el código de Ruby? –

+1

Creo que en 'A.instance_eval', ¿quiso escribir' #defs aquí, vaya a la clase E de A' ¿O estoy equivocado? –

+0

No es exactamente simple, publicaré algunos enlaces relevantes en la respuesta –

3

sólo para añadir a la respuesta de @ krusty.ar: def y define_method añadir métodos para el contexto definición método actual (creo que eso es lo se llama, no estoy seguro), no a la actual self.

Es solo que dentro de un módulo, clase o cuerpo de clase singleton, esos dos son los mismos.

Pero, por ejemplo, en un cuerpo de script (también conocido como nivel superior), self es el objeto main, pero el contexto de definición de método actual es Object.

Cuestiones relacionadas