2010-07-03 10 views
17

La metaprogrammazione in ruby ​​è ottima perché la utilizzo costantemente per emulare la programmazione basata su prototipi e scrivere rapidamente soluzioni prototipo per verificare la loro validità. Quindi vorrei sapere se c'è qualche differenza essenziale tra le seguenti parti di codice:Metodi ruby ​​singleton con (class_eval, define_method) vs (instance_eval, define_method)

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

e

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

Entrambe le versioni del codice di definire un metodo singleton e non ho ancora venire contro tutto ciò che mi ha costretto a scegliere la combinazione (instance_eval, define_method) sulla combinazione (class_eval, define_method) per definire un metodo singleton e mi chiedo se ci sia qualche differenza essenziale tra i due.

+1

Nota che il modo migliore per ottenere il risultato è semplicemente 'define_singleton_method (: method_name) do ... FINE' –

risposta

21

Nessuna differenza per define_method. Ma c'è una differenza quando si utilizza 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 

Perché la differenza di comportamento tra def e define_method? define_method è una chiamata di metodo e quindi opera su self nel contesto di valutazione. Lo self in entrambi gli standard instance_eval e class_eval è lo stesso: è il ricevitore (l'eigenclass di o).

Tuttavia, def si comporta in modo diverso, non funziona su self ma sul default definee. Nel caso di class_eval lo default definee è lo stesso di self ma per instance_eval è invece il metaclasse di self.

Come accedere al metodo test2 definito in precedenza? test2 deve essere un metodo di istanza definito sulla metaclasse dell'eigenclass di o.

Si tratta di un metodo di classe sui eigenclass di O:

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