2012-02-22 11 views
12
class String 
    def hello 
    "world" 
    end 
end 

String.class_eval { 
    def world 
    "hello" 
    end 
} 

"a".world 
=> "hello" 
"b".hello 
=> "world" 

Sembra che facciano la stessa cosa, aggiungendo un metodo a una classe esistente. Quindi qual è la differenza?patching scimmia vs class_eval?

risposta

12

Con class_eval si possono fare cose più dinamiche:

>> met = "hello" #=> "hello" 
>> String.class_eval "def #{met} ; 'hello' ; end" #=> nil 
>> "foo".hello #=> "hello" 
11

class_eval fare concettualmente riapertura classe (o patch scimmia). Esistono principalmente differenze sintattiche. Se si passa la stringa a class_eval (come nell'esempio di Michael) si ha per lo più la stessa sintassi all'interno della stringa come in class String; ... end. Se si passa a blocchi: String.class_eval { ... } si confronta come segue:

  • all'interno del blocco class_eval variabili locali esterni sono visibili
  • all'interno della classe riaperto le variabili locali esterni non sono visibili
  • all'interno class_eval Non è possibile assegnare le costanti e le variabili di classe con ambito alla classe
  • dentro classe riaperto POTETE

sarebbe interessante conoscere le altre differenze

0

Altre risposte sono buone. Si desidera aggiungere che class_eval può essere utilizzato quando si desidera che la classe di riferimento non sia costante o che rappresenti un oggetto particolare.

ad es.

huh = String 
class huh 
end 
SyntaxError: (eval):2: class/module name must be CONSTANT 

huh.class_eval <<-eof 
def mamma 
puts :papa 
end 
eof 

"asdff".mamma 
=> papa 

È possibile utilizzare class_eval di patch particolare oggetto senza affectin classe radice intera.

obj = "asd" 
obj.singleton_class.class_eval <<-eof 
def asd 
puts "gah" 
end 
undef_method :some_method 

Quanto sopra è uguale a:

class << obj 
    ... 
end 

instance_eval avrà un comportamento leggermente differente da qualche uso.

Trovo questa domanda e risposte interessanti: How to monkey patch a ruby class inside a method

Inoltre c'erano domande su instance_eval vs class_eval ma io non avere un link a portata di mano.

Problemi correlati