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

String.class_eval { 
    def world 
    "hello" 
    end 
} 

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

Wydają się robić to samo - dodając metodę do istniejącej klasy. Jaka jest różnica?małpa łatanie vs class_eval?

Odpowiedz

12

Z class_eval można zrobić bardziej dynamiczne rzeczy:

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

class_eval zrobić konceptualną klasa ponownego otwarcia (lub małpa łatanie). W większości występują różnice składniowe. Jeśli podasz ciąg znaków do class_eval (jak w przykładzie Michaela), masz w swojej strukturze w większości taką samą składnię jak w class String; ... end. Jeśli zdasz bloku: String.class_eval { ... } porównuje się następująco:

  • wewnątrz class_eval blokowe zewnętrzne zmienne lokalne są widoczne
  • wewnątrz ponownie klasowych zewnętrznych zmienne lokalne nie są widoczne
  • wewnątrz class_eval nie można przypisać stałe i zmienne klasy scoped do klasy
  • wewnątrz odnowieniem klasy możesz

byłoby interesujące dowiedzieć się inne różnice

0

Inne odpowiedzi są dobre. Chcesz dodać, że class_eval może być użyty, gdy chcesz, aby klasa odniesienia nie była stała lub łatała dany obiekt.

np.

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 

Można użyć class_eval załatać konkretny obiekt bez affectin całej klasy root.

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

Powyższe jak poniżej:

class << obj 
    ... 
end 

instance_eval będą miały nieco odmienne zachowanie od pewnego stosowania.

uważam to pytanie za interesujący: How to monkey patch a ruby class inside a method

Również tam były pytania o instance_eval vs class_eval ale nie mam link pod ręką.

Powiązane problemy