特殊类型的 eval
eval
相关的一些变体以名为 instance_eval
,module_eval
和 class_eval
方法的形式出现。可以从特定对象调用 instance_eval
方法,并且它提供对该对象的实例变量的访问。它可以用块或字符串调用:
class MyClass
def initialize
@aVar = "Hello world"
end
end
ob = MyClass.new
p( ob.instance_eval { @aVar } ) #=> "Hello world"
p( ob.instance_eval( "@aVar" ) ) #=> "Hello world"
另一方面,eval
方法不能以这种方式从对象调用,因为它是 Object 的私有方法(而 instance_eval
是公有方法)。实际上,你可以通过将其名称(符号 :eval
)发送到 public
方法来显式更改 eval
的可见性,尽管通常建议不要在基类中没有理由的去更改方法可见性!
eval
是 Kernel 模块的一个方法,它是被混入到 Object 类中的。事实上,Kernel 模块提供了大多数可用作 Object 方法的函数。你可以通过以这种方式添加到 Object 类定义来更改 eval
的可见性:
class Object
public :eval
end
实际上,请记住,当你编写“独立”的代码时,你实际上是在 Object 的作用域内工作,只需输入此代码(没有类 Object 包装器)就会产生相同的效果:
public :eval
现在你可以使用 eval
作为 ob
变量的方法:
p( ob.eval( "@aVar" ) ) #=> "Hello world"
module_eval
和 class_eval
方法分别对模块和类而不是对象进行操作。例如,此代码将 xyz
方法添加到 X 模块(此处 xyz
在块中定义,并通过 define_method
作为接收对象的实例方法添加,这是 Module 类的方法);并将 abc
方法添加到 Y 类:
module X
end
class Y
@@x = 10
include X
end
X::module_eval{ define_method(:xyz){ puts("hello" ) } }
Y::class_eval{ define_method(:abc){ puts("hello, hello" ) } }
::
或单个点。访问常量时,作用域解析运算符是必需的,访问方法时是可选的。所以,现在作为 Y 实例的对象将有权访问 Y 类的 abc
方法和已混合到 Y 类中的 X 模块的 xyz
方法:
ob = Y.new
ob.xyz #=> "hello"
ob.abc #=> "hello, hello"
尽管名称不同,但 module_eval
和 class_eval
在功能上是相同的,并且每个都可以与模块或类一起使用:
X::class_eval{ define_method(:xyz2){ puts("hello again" ) } }
Y::module_eval{ define_method(:abc2){ puts("hello, hello again" ) } }
你也可以以相同的方式将方法添加到 Ruby 的标准类中:
String::class_eval{ define_method(:bye){ puts("goodbye" ) } }
"Hello".bye #=> "goodbye"