为什么eval创建方法作为私有方法?

时间:2012-09-19 17:24:36

标签: ruby metaprogramming

这段代码将方法创建为私有方法,为什么?

a = %q{def hello() "Hello there!" end}
class A; end
A.class.send(:eval, a)
A.new.hello #=> NoMethodError: private method `hello' called for A

平台:ruby 1.9.3p125,在pry

中测试

1 个答案:

答案 0 :(得分:5)

在任何模块之外定义的方法(所谓的全局方法)实际上被定义为Object的私有实例方法。这样,可以随处调用(因为所有内容都来自Object),并且只能在没有显式接收器的情况下调用它们。

这包括requireloadputsprintpgetseval等方法。 (注意:其中大多数实际Kernel中定义并混合到Object但效果和目标是相同的。)

在您的情况下, 定义任何模块之外的方法:a字符串中没有提及模块。您在eval上致电A.class这一事实完全无关紧要。就像我上面所说:eval是一个在Object上定义的全局方法,出于方便的原因(因此可以在任何地方调用它)。您的A.class.send(:eval)只是调用全局私有eval方法的一种非常复杂的方式。它并没有以某种方式神奇地将eval uated字符串的上下文设置为A.class

您可以改为42.send(:eval),结果仍然相同,就像puts('Hello')42.send(:puts, 'Hello')完全相同,因为它们最终会调用完全相同的方法。< / p>

顺便说一下:即使它做了,它仍然不会做你想要的。 A.class只是Class任何类的class 总是 Class),所以如果 按预期工作,该方法将在Class中定义,而不是在A中定义。