正如文档所说,class_eval
在模块或类的上下文中评估字符串或块。所以下面的代码是等价的:
class String
def lowercase
self.downcase
end
end
String.class_eval do
def lowercase
self.downcase
end
end
在每种情况下,String 类都被重新打开并定义了一个新方法。该方法可在该类的所有实例中使用,因此:
"This Is Confusing".lowercase
=> "this is confusing"
"The Smiths on Charlie's Bus".lowercase
=> "the smiths on charlie's bus"
class_eval
与简单地重新开课相比,有很多优点。首先,您可以轻松地在变量上调用它,并且很清楚您的意图是什么。另一个优点是,如果该类不存在,它将失败。所以下面的例子将会失败Array
拼写错误。如果简单地重新开放该课程,它就会成功(并且会出现一个新的错误Aray
类将被定义):
Aray.class_eval do
include MyAmazingArrayExtensions
end
Finally class_eval
可以接受一个字符串,如果你正在做一些更邪恶的事情,这会很有用......
instance_eval
另一方面,针对单个对象实例评估代码:
confusing = "This Is Confusing"
confusing.instance_eval do
def lowercase
self.downcase
end
end
confusing.lowercase
=> "this is confusing"
"The Smiths on Charlie's Bus".lowercase
NoMethodError: undefined method ‘lowercase’ for "The Smiths on Charlie's Bus":String
So with instance_eval
,该方法仅为字符串的单个实例定义。
那么为什么instance_eval
on a Class
定义类方法?
Just as "This Is Confusing"
and "The Smiths on Charlie's Bus"
都是String
实例,Array
, String
, Hash
所有其他类本身都是Class
。您可以通过致电来检查这一点#class
在他们:
"This Is Confusing".class
=> String
String.class
=> Class
所以当我们打电话时instance_eval
它对类的作用与对任何其他对象的作用相同。如果我们使用instance_eval
要在类上定义方法,它将仅为该类的实例而不是所有类定义方法。我们可以将该方法称为类方法,但它只是该特定类的实例方法。