在下面的代码中使用include模块。如果删除了包含模块的方式,那么也会创建一个实例方法。那么为什么用户包含模块?
http://github.com/rails/rails/blob/master/activerecord/lib/active_record/associations.rb#L1416
include Module.new {
class_eval <<-RUBY, __FILE__, __LINE__ + 1
def destroy # def destroy
super # super
#{reflection.name}.clear # posts.clear
end # end
RUBY
}
答案 0 :(得分:12)
首先让我们说清楚一件事。当他们在super
内拨打class_eval
时,它与他们使用include Module.new {}
事物的原因完全无关。事实上,在super
方法中调用的destroy
与回答您的问题完全无关。在destroy方法中可能有任意代码。
现在我们已经解决了问题,这就是正在发生的事情。
在ruby中,如果您只是定义一个类方法,然后在同一个类中再次定义它,那么您将无法调用super
来访问上一个方法。
例如:
class Foo
def foo
'foo'
end
def foo
super + 'bar'
end
end
Foo.new.foo # => NoMethodError: super: no superclass method `foo' for #<Foo:0x101358098>
这是有道理的,因为第一个foo
没有在某个超类中定义,或者在查找链的任何地方定义(super
指向的位置)。但是,您可以定义第一个foo
,以便以后覆盖它时 - 通过调用super
可以使用它。这正是他们想要用模块包含的目的。
class Foo
include Module.new { class_eval "def foo; 'foo' end" }
def foo
super + 'bar'
end
end
Foo.new.foo # => "foobar"
这很有效,因为当你包含一个模块时,ruby会将它插入到查找链中。这样,您可以随后在第二种方法中调用super
,并期望调用包含的方法。大。
然而,您可能想知道,为什么不简单地包含一个没有所有技巧的模块?他们为什么使用块语法?我们知道上面的示例完全等同于以下内容:
module A
def foo
'foo'
end
end
class Foo
include A
def foo
super + 'bar'
end
end
Foo.new.foo # => "foobar"
那他们为什么不这样做呢?答案是 - 致电reflection
。他们需要捕获当前上下文中可用的变量(或方法),即reflection
。
由于他们使用块语法定义新模块,因此块内的所有变量都可用于块内。方便。
只是为了说明。
class Foo
def self.add_foo_to_lookup_chain_which_returns(something)
# notice how I can use variable something in the class_eval string
include Module.new { class_eval "def foo; '#{something}' end" }
end
end
# so somewhere else I can do
class Foo
add_foo_to_lookup_chain_which_returns("hello")
def foo
super + " world"
end
end
Foo.new.foo # => "hello world"
干净,呵呵?
现在让我再强调一下。在您的示例中,super
方法内的destroy
调用与上述任何内容无关。他们出于自己的原因调用它,因为可能发生这种情况的类正在继承另一个已定义destroy
的类。
我希望这说清楚。
答案 1 :(得分:0)
我猜测但是......他们不想覆盖“破坏”方法,并希望让某些最终用户(你或我)重载它,而不会删除这个“反射” .clear“功能。
所以 - 通过将它包含为模块,他们可以调用“super”来调用原始的destroy 或重载的版本(由最终用户编写)。
答案 2 :(得分:0)
感谢include
,destroy
方法未被覆盖。它落在实际类派生的幽灵类中。这样,当一个人在AR对象上调用destroy
时,将调用原始的一个,super
将从匿名模块调用一个(稍后将调用原始 {{1}从它派生的类开始。)
确实有点棘手。