代码之家  ›  专栏  ›  技术社区  ›  Nick Vanderbilt

为什么要使用include模块,而class\u eval本身就足够了

  •  7
  • Nick Vanderbilt  · 技术社区  · 15 年前

    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
            }
    
    3 回复  |  直到 15 年前
        1
  •  12
  •   Max Chernyak    15 年前

    首先让我们弄清楚一件事。当他们打电话的时候 super 内部 class_eval include Module.new {} 事情。事实上 它被称为 destroy 方法和回答你的问题完全无关。销毁方法中可能有任意代码。

    在ruby中,如果您只是定义一个class方法,然后在同一个类中再次定义它,您将无法调用

    例如:

    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 未在某个超类或查找链上的任何位置(即 点数)。然而,你 可以 定义第一个 这样,当您稍后覆盖它时,可以通过调用 超级的

    class Foo
      include Module.new { class_eval "def foo; 'foo' end" }
    
      def foo
        super + 'bar'
      end
    end
    
    Foo.new.foo # => "foobar"
    

    超级的

    module A
      def foo
        'foo'
      end
    end
    
    class Foo
      include A
    
      def foo
        super + 'bar'
      end
    end
    
    Foo.new.foo # => "foobar"
    

    那他们为什么不这么做呢?答案是呼吁 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"
    

    不错吧?

    超级的 内部 破坏 .

    我希望这能说明问题。

        2
  •  0
  •   Taryn East    15 年前

    我猜但是。。。他们不想覆盖“destroy”方法,想让它被某个最终用户(你或我)重载,而不让它删除这个“reflection.clear“功能。

    所以-通过将它作为一个模块,他们可以称之为“超级”,这将称之为原始销毁 重载版本(由最终用户编写)。

        3
  •  0
  •   samuil    15 年前

    感谢 include destroy 方法未被覆盖。它落在实际类派生的幽灵类中。那样的话,当有人打电话的时候 在AR对象上,将调用原始对象,并且 super 将从匿名模块(稍后将调用