Estoy leyendo la documentación de Module
pero no puedo entender sus diferencias y cuál debería usarse donde.¿Cuál es la diferencia entre class_eval, class_exec, module_eval y module_exec?
¿En qué se diferencia el eval
de exec
?
Estoy leyendo la documentación de Module
pero no puedo entender sus diferencias y cuál debería usarse donde.¿Cuál es la diferencia entre class_eval, class_exec, module_eval y module_exec?
¿En qué se diferencia el eval
de exec
?
Voy a responder un poco más que su pregunta al incluir instance_{eval|exec}
en su pregunta.
Todas las variaciones de {instance|module|class}_{eval|exec}
cambio la contexto actual, es decir, el valor para self
:
class Array
p self # prints "Array"
43.instance_eval{ p self } # prints "43"
end
ya por las diferencias. Las versiones eval
acepta una cadena o un bloque, mientras que las versiones exec
sólo aceptan un bloque, pero le permiten pasar parámetros a la misma:
def example(&block)
42.instance_exec("Hello", &block)
end
example{|mess| p mess, self } # Prints "Hello" then "42"
La versión eval
no permite pasar parámetros. Proporciona self
como primer parámetro, aunque no puedo pensar en un uso para esto.
Finalmente, module_{eval|exec}
es el mismo que el correspondiente class_{eval|exec}
, pero son ligeramente diferentes de instance_{eval|exec}
a medida que cambian lo que es la clase corriente abierta (es decir, lo que se verá afectado por def
) de diferentes maneras:
String.instance_eval{ def foo; end }
Integer.class_eval { def bar; end }
String.method_defined?(:foo) # => false
String.singleton_methods.include?(:foo) # => true
Integer.method_defined?(:bar) # => true
Entonces obj.instance_{eval|exec}
abre la clase singleton de obj
, mientras que mod.{class|module}_{eval|exec}
abre mod
.
Por supuesto, instance_{eval|exec}
están disponibles en cualquier objeto Ruby (incluyendo módulos), mientras que {class|module}_*
sólo están disponibles en Module
(y por lo tanto Classes
)
Para responder a su última pregunta primero, eval (en todas sus variaciones) es completamente diferente de la ejecutiva. exec $command
comenzará un nuevo proceso para ejecutar el comando que especifique y luego saldrá cuando termine.
class_eval
y module_eval
tienen el poder de redefinir las clases y módulos, incluso aquellos que usted mismo no escribió. Por ejemplo, puede usar eval de clase para agregar un nuevo método que no existía.
Fixnum.class_eval { def number; self; end }
7.number # returns '7'
class_eval
se puede utilizar para añadir métodos de instancia, y instance_eval
se puede utilizar para añadir métodos de clase (sí, esa parte es muy confuso). Un método de clase sería algo así como Thing.foo
- literalmente está llamando al método foo
en la clase Thing
. Un método de instancia es como el ejemplo anterior, usando class_eval
Agregué un método number
a cada instancia de Fixnum
.
Bien, esa es la clase de métodos *_eval
. Los métodos de ejecución son similares, pero le permiten mirar dentro de una clase y ejecutar un bloque de código como si estuviera definido como un método en esa clase. Tal vez usted tiene una clase que tiene este aspecto:
class Foo
@@secret = 'secret key'
@@protected = 'some secret value'
def protected(key)
if key == @@secret
return @@protected
end
end
end
La clase Foo
es sólo un envoltorio alrededor de algún valor secreto, si conoce la clave correcta. Sin embargo, se puede engañar a la clase en que le da sus secretos mediante la ejecución de un bloque dentro del contexto de la clase, así:
Foo.class_exec { @@secret = 'i'm a hacker' }
Foo.protected('i'm a hacker') #returns the value of @@protected because we overwrote @@secret
En general, con una gran cantidad de las herramientas de rubí, se puede usar cualquiera de estos para resolver muchos problemas Es probable que muchas veces ni siquiera necesites hacerlo a menos que quieras parche de mono una clase que haya definido alguna biblioteca (aunque eso abre una gran cantidad de gusanos). Intente jugar con ellos en irb y vea cuál le resulta más fácil. Personalmente, no uso los métodos *_exec
tanto como los métodos *_eval
, pero esa es una preferencia personal mía.
Creo que estás confundiendo '' exec' y instance_exec' –
En realidad, no ? Mencioné 'exec' explícitamente al principio. 'exec' en realidad no tiene mucho en común con la familia de métodos' eval', tanto como '{instance | module | class} _exec' do. – tjarratt
Oh, ya veo. Creo que el OP significa '* _eval' vs' * _exec', no 'eval' vs' exec', pero podría estar equivocado. –
Nota: cuando module_eval lambda, pasa el módulo a lambda como primer parámetro. module_exec no. – Nakilon
No me di cuenta de eso. No puedo pensar en un solo caso en el que sea útil (en su lugar, use 'self'), pero he editado mi respuesta para que esté completa. –