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

String.class_eval { 
    def world 
    "hello" 
    end 
} 

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

Aynı şeyi yapıyorlar - var olan bir sınıfa bir yöntem ekliyorlar. Peki fark nedir?monkey patching vs class_eval?

cevap

12

class_eval ile daha dinamik şeyler yapabilirsiniz:

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

kavramsal sınıf yeniden açılma (veya maymun yama) yapmak class_eval. Çoğunlukla sözdizimsel farklılıklar vardır. Dizeyi class_eval'a iletirseniz (örneğin Michael'ın örneğinde olduğu gibi), çoğunlukla dizenin içinde class String; ... end'daki gibi aynı sözdizimi vardır. Eğer blok geçerseniz: String.class_eval { ... } aşağıdaki gibi karşılaştırır:

  • içindeki class_eval blok dış yerel değişkenler yeniden açıldı sınıf dış yerel değişkenler içine
  • görebilir
  • içeride sen kapsamlı sabitleri ve sınıf değişkenleri atamak CAN NOT class_eval görünür DEĞİLDİR sınıfın yeniden açıldı sınıf içinde
  • sizin

diğer farklılıkları bilmek ilginç olurdu CAN

0

Diğer cevaplar iyidir. class_eval'un referans sınıfını sabit olarak değil veya belirli bir nesneyi yamalamak istediğinizde kullanabileceğini eklemek ister.

örn.

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 

Sen affectin bütün kök sınıfın olmadan belirli bir nesne yama class_eval kullanabilirsiniz.

class << obj 
    ... 
end 

instance_eval bir kullanımına göre biraz daha farklı bir davranış olacaktır: olarak

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

yukarıda

aynıdır. How to monkey patch a ruby class inside a method

Ayrıca instance_eval vs class_eval ilgili sorular vardı ama bir bağlantı kullanışlı yok:

ilginç bu soruyu ve yanıtlarını bulmak.