在下面的代码中使用了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 }
解决方法
@H_404_9@ 首先让我们说清楚一件事.当他们在class_eval中调用super时 – 它与他们使用的包含Module.new {}的东西完全无关.实际上,在destroy方法中调用的super与回答你的问题完全无关. 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没有在某个超类中定义,也没有在查找链的任何地方定义(这是超级点的位置).但是,您可以通过以下方式定义第一个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"
那他们为什么不这样做呢?答案是 – 反思的呼唤.他们需要捕获当前上下文中可用的变量(或方法),即反射.
由于它们使用块语法定义新模块,因此块内的所有变量都可用于块内.方便.
只是为了说明.
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"
整洁,对吧?
现在让我再强调一下.在您的示例中对destroy方法的super调用与上述任何内容无关.他们出于自己的原因调用它,因为可能发生这种情况的类正在继承另一个已经定义了destroy的类.
我希望这说清楚.