2012-04-24 14 views
7

¿Hay alguna diferencia en cómo funciona class_eval & instance_eval excepto def? Dentro del class_eval, el bloque def define el método para clasificarse a sí mismo (es decir, el método de instancia) y dentro de instance_evaldef define el método para la clase de clase (es decir, el método de clase). AFAIK todas las demás características funcionan de forma idéntica en ambos casos (por ejemplo, define_method, attr_accessor, class << self; end, definiendo constantes). ¿Es verdad?class_eval vs instance_eval

respuesta es: def, undef y alias tienen diferentes contextos para class_eval y instance_eval.

Respuesta

13

Para resumir:

  • (object = Object.new).instance_eval &block conjuntos:
  • Object.class_eval &block conjuntos:
    • self-Object
    • La "clase actual" para Object

La "clase actual" se utiliza para def, undef y alias, así como operaciones de búsqueda variables constantes y de clase.


Ahora, echemos un vistazo a los detalles de implementación.

Así es como module_eval y instance_eval se implementan en C:

VALUE rb_mod_module_eval(int argc, VALUE *argv, VALUE mod) { 
    return specific_eval(argc, argv, mod, mod); 
} 

VALUE rb_obj_instance_eval(int argc, VALUE *argv, VALUE self) { 
    VALUE klass; 
    if (SPECIAL_CONST_P(self)) { klass = Qnil; } 
    else { klass = rb_singleton_class(self); } 
    return specific_eval(argc, argv, klass, self); 
} 

Tanto llamada specific_eval, que tiene los siguientes argumentos: int argc, VALUE *argv, VALUE klass y VALUE self.

en cuenta que:

  • module_eval pasa la instancia Module o Class como tanto klassyself
  • instance_eval pasa clase singleton del objeto como klass

Si se les da un bloque , specific_eval llamará al yield_under, que toma los siguientes argumentos: VALUE under, VALUE self y VALUE values.

if (rb_block_given_p()) { 
    rb_check_arity(argc, 0, 0); 
    return yield_under(klass, self, Qundef); 
} 

Hay dos líneas importantes en yield_under:

  1. block.self = self;

    Esto establece el self del bloque para el receptor.

  2. cref = vm_cref_push(th, under, NOEX_PUBLIC, blockptr);

    El cref es una lista vinculado que especifica la "clase actual", que se utiliza para def, undef y alias, así búsquedas de variables como constantes y de clase.

    Esa línea básicamente establece cref en under.

    Por último:

    • cuando se llama desde module_eval, under será el Class o Module ejemplo.

    • Cuando se llama desde instance_eval, under será la clase Singleton de self.

+1

hay una cosa: en el interior 'class_eval' asignar constantes y variables de clase no funciona de la forma en que funciona en la definición de la clase/reapertura: se usa el alcance externo. – Alexey

+0

@Alexey, tienes razón. Apuesto a que tiene algo que ver con la constante 'NODE_FL_CREF_PUSHED_BY_EVAL'. Muchos métodos, como ['Module :: nesting'] (http://ruby-doc.org/core-1.9.3/Module.html#method-c-nesting) por ejemplo, parecen ignorar un nodo' cref' si la bandera está configurada –

0

instance_eval le permite acceder directamente a las variables de instancia de la instancia y usar self como referencia a la instancia.

+1

'' class_eval' y el trabajo instance_eval' idéntica al respecto – Alexey

Cuestiones relacionadas