[英]instance_eval vs class_eval in module
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
Notice here I changed class_eval to instance_eval 请注意,我将class_eval更改为instance_eval
Foo.new.lab rescue nil#=> no super class method lab
Foo.lab #=> undefined method lab for Foo class
So it seems that including the module neither defined an instance method nor a class method. 所以似乎包含模块既没有定义实例方法也没有定义类方法。
Any explanation what's going on here? 有什么解释在这里发生了什么?
This code was tested on ruby 1.8.7 on mac. 此代码在mac上的ruby 1.8.7上进行了测试。
First, think of what include
does. 首先,想到什么
include
呢。 it makes the instance methods of the module being included into instance methods on the including class. 它使模块的实例方法被包含在包含类的实例方法中。 ie apart from the fact that your working example uses an anonymous module it is equivalent to:
即,除了您的工作示例使用匿名模块这相当于:
module M1
def lab
puts 'm'
end
end
class Foo
include M1
def lab
super
puts 'c'
end
end
Next, think of what class_eval
does. 接下来,想一想
class_eval
作用。 It evaluates the given code in the context of the class or module. 它在类或模块的上下文中评估给定的代码。 ie it's exactly like you reopened the module and typed the code passed to
class_eval
. 即它就像你重新打开模块并输入传递给
class_eval
的代码class_eval
。 So MyModule = Module.new { class_eval "def lab; puts 'm' end" }
is equivalent to 所以
MyModule = Module.new { class_eval "def lab; puts 'm' end" }
相当于
module MyModule
def lab
puts 'm'
end
end
Hopefully this explains the case that works. 希望这能解释有效的案例。
When you use instance_eval
you are evaluating the code within the context of the receiving object (in this case the instance of module) so MyMod2 = Module.new { instance_eval "def lab; puts 'm' end" }
is equivalent to 当你使用
instance_eval
你正在评估接收对象的上下文中的代码(在这种情况下是模块的实例)所以MyMod2 = Module.new { instance_eval "def lab; puts 'm' end" }
相当于
module MyMod2
def MyMod2.lab
puts 'm'
end
end
ie it creates a module method which you'd call via MyMod2.lab
and such methods are not added as instance methods by include
. 即它创建了一个模块方法,您可以通过
MyMod2.lab
调用MyMod2.lab
并且这些方法不会被include
作为实例方法include
。
Please note : this answer borrows a bit of its explanation from an answer I wrote to a previous question asking about instance_eval vs. class_eval relating to an example from The Ruby Programming Language book. 请注意 :这个答案从我写给前一个问题的答案中借用了一些解释,这个问题询问了与 Ruby编程语言书中的一个例子有关的instance_eval与class_eval 。 You might find that answer helpful too.
您可能会发现答案也很有用。
including a module just takes the instance methods - you are looking for extend. 包括一个模块只需要实例方法 - 你正在寻找扩展。 luckily to get the best of both worlds, you can simply do:
幸运的是,为了获得两全其美,你可以简单地做到:
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: IRB:
>> Test.blah
lol
=> nil
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.