class String
def hello
"world"
end
end
String.class_eval {
def world
"hello"
end
}
"a".world
=> "hello"
"b".hello
=> "world"
他们似乎做同样的事情 - 向现有类添加方法。那有什么区别?
答案 0 :(得分:13)
使用class_eval
,你可以做更多动态的事情:
>> met = "hello" #=> "hello"
>> String.class_eval "def #{met} ; 'hello' ; end" #=> nil
>> "foo".hello #=> "hello"
答案 1 :(得分:13)
class_eval在概念上进行类重新打开(或猴子修补)。主要是语法差异。如果将字符串传递给class_eval
(如Michael的示例中所示),则字符串内部的语法与class String; ... end
中的语法大致相同。如果你传递阻止:String.class_eval { ... }
,则按如下方式进行比较:
了解其他差异会很有趣
答案 2 :(得分:0)
其他答案都很好。想要添加class_eval
可以在您希望引用类不是通过常量或修补特定对象时使用。
e.g。
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
您可以使用class_eval
修补特定对象而不影响整个根类。
obj = "asd"
obj.singleton_class.class_eval <<-eof
def asd
puts "gah"
end
undef_method :some_method
以上内容与:
相同class << obj
...
end
instance_eval
会因某些用法而略有不同。
我觉得这个问题和答案很有趣: How to monkey patch a ruby class inside a method
还有关于instance_eval
与class_eval
的问题,但我没有方便的链接。