首先让我们澄清一件事。当他们在class_eval 中调用super 时——这与他们使用include 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 没有在某个超类中定义,也没有在查找链上的任何地方定义(这是 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"
整洁,嗯?
现在让我再次强调一下。在您的示例中,在 destroy 方法内对 super 的调用与上述任何内容无关。他们出于自己的原因调用它,因为可能发生这种情况的类是另一个已经定义 destroy 的类的子类。
我希望这能说清楚。