Nic*_*ilt 7 ruby ruby-on-rails
在下面的代码中使用了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
}
Run Code Online (Sandbox Code Playgroud)
Max*_*yak 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>
Run Code Online (Sandbox Code Playgroud)
这是有道理的,因为第一个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"
Run Code Online (Sandbox Code Playgroud)
这是有效的,因为当您包含模块时,ruby会将其插入到查找链中.这样,您可以随后调用super第二种方法,并期望调用包含的方法.大.
但是,您可能想知道,为什么不简单地包含一个没有所有技巧的模块?他们为什么使用块语法?我们知道上面的例子完全等同于以下内容:
module A
def foo
'foo'
end
end
class Foo
include A
def foo
super + 'bar'
end
end
Foo.new.foo # => "foobar"
Run Code Online (Sandbox Code Playgroud)
那他们为什么不这样做呢?答案是 - 致电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"
Run Code Online (Sandbox Code Playgroud)
整洁,对吧?
现在让我再强调一下.在您的示例super中对destroy方法内部的调用与上述任何内容无关.他们出于自己的原因调用它,因为可能发生这种情况的类正在继承另一个已定义的类destroy.
我希望这说清楚.