ruby-on-rails – 当class_eval本身足够时,为什么要使用include模块

在下面的代码中使用了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
        }

解决方法

首先让我们说清楚一件事.当他们在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的类.

我希望这说清楚.

相关文章

validates:conclusion,:presence=>true,:inclusion=>{...
一、redis集群搭建redis3.0以前,提供了Sentinel工具来监控各...
分享一下我老师大神的人工智能教程。零基础!通俗易懂!风趣...
上一篇博文 ruby传参之引用类型 里边定义了一个方法名 mo...
一编程与编程语言 什么是编程语言? 能够被计算机所识别的表...
Ruby类和对象Ruby是一种完美的面向对象编程语言。面向对象编...