class Foo
include Module.new { class_eval "def lab; puts 'm' end" }
def lab
super
puts 'c'
end
end
Foo.new.lab #=> m c
=============================================== =========================
class Foo
include Module.new { instance_eval "def lab; puts 'm' end" }
def lab
super
puts 'c'
end
end
请注意,我将class_eval更改为instance_eval
Foo.new.lab rescue nil#=> no super class method lab
Foo.lab #=> undefined method lab for Foo class
所以似乎包含模块既没有定义实例方法也没有定义类方法。
有什么解释在这里发生了什么?
此代码在mac上的ruby 1.8.7上进行了测试。
答案 0 :(得分:9)
首先,想一想include
的作用。它使模块的实例方法包含在包含类的实例方法中。即,除了您的工作示例使用匿名模块之外,它等同于:
module M1
def lab
puts 'm'
end
end
class Foo
include M1
def lab
super
puts 'c'
end
end
接下来,想一想class_eval
的作用。它在类或模块的上下文中评估给定的代码。即它就像你重新打开模块并输入传递给class_eval
的代码一样。所以MyModule = Module.new { class_eval "def lab; puts 'm' end" }
相当于
module MyModule
def lab
puts 'm'
end
end
希望这可以解释有效的案例。
使用instance_eval
时,您正在评估接收对象上下文中的代码(在本例中为模块实例),因此MyMod2 = Module.new { instance_eval "def lab; puts 'm' end" }
等同于
module MyMod2
def MyMod2.lab
puts 'm'
end
end
即。它会创建一个模块方法,您可以通过MyMod2.lab
调用该方法,并且include
不会将此类方法作为实例方法添加。
请注意:这个答案从我写给previous question asking about instance_eval vs. class_eval的答案中借用了一些解释,该答案与 Ruby Programming Language 书中的一个例子有关。您可能会发现这个答案也很有帮助。
答案 1 :(得分:3)
包括一个模块只需要实例方法 - 你正在寻找扩展。幸运的是,为了获得两全其美,你可以简单地做到:
module Something
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
def blah
puts "lol"
end
end
end
class Test
include Something
end
IRB:
>> Test.blah
lol
=> nil