2012-04-24 13 views
7

C'è qualche differenza nel modo in cui class_eval & instance_eval funziona tranne def? Dentro il blocco class_eval il metodo def definisce il metodo per classificare sé stesso (ad esempio il metodo di istanza) e all'interno di instance_evaldef definisce il metodo per l'eigenclass della classe (ad esempio il metodo di classe). AFAIK tutte le altre funzioni funzionano in modo identico in entrambi i casi (ad esempio define_method, attr_accessor, class << self; end, definizione di costanti). È vero?class_eval vs instance_eval

risposta è: def, undef e alias hanno diversi contesti per class_eval e instance_eval.

risposta

13

Per farla breve:

  • (object = Object.new).instance_eval &block set:
  • Object.class_eval &block set:
    • self a Object
    • La "classe corrente" per Object

La "classe corrente" viene utilizzato per def, undef e alias, nonché le ricerche variabili e costanti di classe.


Ora, diamo un'occhiata ai dettagli di implementazione.

Ecco come module_eval e instance_eval sono implementate in 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); 
} 

Entrambi chiamata specific_eval, che accetta i seguenti argomenti: int argc, VALUE *argv, VALUE klass e VALUE self.

noti che:

  • module_eval passa l'istanza Module o Class sia come klasseself
  • instance_eval passa classe singleton dell'oggetto come klass

Se in un blocco , specific_eval chiamerà yield_under, che accetta i seguenti argomenti: VALUE under, VALUE self e VALUE values.

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

Ci sono due linee importanti yield_under:

  1. block.self = self;

    Imposta la self del blocco al ricevitore.

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

    Il cref è una lista collegata che specifica la "classe di", che viene utilizzato per def, undef e alias, nonché ricerche variabili come costanti e di classe.

    Questa riga imposta in pratica lo cref su under.

    Infine:

    • Quando chiamato da module_eval, under sarà l'istanza Class o Module .

    • Quando viene chiamato da instance_eval, under sarà la classe Singleton di self.

+1

c'è una cosa: dentro 'class_eval' assegnazione di costanti e variabili di classe non funziona il modo in cui funziona nella definizione di classe/riapertura: si usa l'ambito esterno. – Alexey

+0

@Alexey, hai ragione. Scommetto che ha qualcosa a che fare con la costante di 'NODE_FL_CREF_PUSHED_BY_EVAL'. Molti metodi, come ['Module :: nesting'] (http://ruby-doc.org/core-1.9.3/Module.html#method-c-nesting), ad esempio, sembrano ignorare un nodo' cref' se la bandiera è impostata. –

0

instance_eval consente di accedere direttamente alle variabili di istanza dell'istanza e utilizzare self come riferimento all'istanza.

+1

'' class_eval' e lavoro instance_eval' modo identico a tal riguardo – Alexey

Problemi correlati