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

String.class_eval { 
    def world 
    "hello" 
    end 
} 

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

그들은 기존의 클래스에 메소드를 추가하는 것과 같은 일을하는 것처럼 보입니다. 차이점은 무엇입니까?원숭이 패치 대 class_eval?

답변

12

class_eval하면 더욱 동적 인 일을 할 수 있습니다

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

개념적 클래스 재개 (또는 원숭이 패치를) 할 class_eval. 구문상의 차이가 대부분 있습니다. 문자열을 class_eval으로 전달하면 (Michael의 예와 같이) 대부분 class String; ... end과 같은 문자열 내부 구문을 사용합니다. 당신이 블록 전달하는 경우 : String.class_eval { ... }를 다음과 같이는 비교 :

  • 내부 class_eval 블록 외부 지역 변수는 재개 클래스 외부 지역 변수 내부
  • 볼 수 있습니다
  • 내부는 범위 상수와 클래스 변수를 할당 할 수 없습니다 class_eval 볼 수 없습니다 클래스 재개 클래스 내부
  • 에 당신은

는 다른 차이점을 알고 재미있을 것 CAN

0

다른 답변은 좋습니다. 추가 하시려는 경우 class_eval은 참조 클래스가 상수가 아니거나 특정 객체를 패치 할 때 사용할 수 있습니다.

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 

당신은 affectin 전체 루트 클래스없이 특정 개체를 패치 class_eval를 사용할 수 있습니다.

class << obj 
    ... 
end 

instance_eval 일부 사용에 의해 약간 다른 동작을해야합니다 :로

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

은 동일합니다. How to monkey patch a ruby class inside a method

는 또한 instance_evalclass_eval에 대한 질문이 있었다하지만 링크가 유용하지 않습니다

나는 흥미있는이 질문에 대한 답을 찾을 수 있습니다.

관련 문제