【问题标题】:Can I overwrite instance method from module?我可以从模块覆盖实例方法吗?
【发布时间】:2014-02-11 13:15:52
【问题描述】:

我知道,我可以这样覆盖模块中的类方法

class Foo
  class << self
    def some_static_method
      puts 'some_static_method'
    end
  end
end

module BAR
  class << Foo
    def some_static_method
      puts 'another_static_method'
    end
  end
end

class Foo
  include BAR
end

Foo.some_static_method # => 'another_static_method'

实例方法可以吗?

【问题讨论】:

  • 您可能会找到一些信息here。

标签: ruby overwrite


【解决方案1】:

您可以执行以下操作:

class Foo
  def self.some_static_method; puts "Hello from Foo" end
end

module Bar
  def self.included(base)
    base.instance_eval do
     def some_static_method; puts "Hello from Bar" end
    end
  end
end

class Foo
  include Bar
end

Foo.some_static_method

这应该可以工作

更新

要覆盖实例方法使用:

class Foo
  def some_instance_method; puts "Hello from Foo" end
end

module Bar
  def self.included(base)
    base.class_eval do
     def some_instance_method; puts "Hello from Bar" end
    end
  end
end

class Foo
  include Bar
end

Foo.new.some_instance_method

【讨论】:

  • 好的。这是覆盖类方法的更优雅的方式。那么,Foo类的实例方法呢?
【解决方案2】:

您的问题实际上与方法覆盖无关。它是关于在模块主体的 class ... 构造中引用的类。

当你这样做时

module Bar
  class << Foo
    p self
  end
end
# => #<Class:Foo>

&lt;&lt; Foo 指向主环境中Foo 的单例类,因为class &lt;&lt; Foo 不能直接定义未预先定义的类Foo 的单例类。所以它会查找已经定义的Foo,并且在主环境中找到了这样的类。

当你这样做时

module Bar
  class Foo
    p self
  end
end
# => Bar::Foo

创建了一个新类Bar::Foo; Foo 指向这个新创建的Bar::Foo,而不是指向主环境中的Foo。为了指向它,您必须使用:: 明确指定它。

module Bar
  class ::Foo
    p self
  end
end
# => Foo

【讨论】:

    【解决方案3】:

    如果您使用的是 Ruby > 2.0.0,那么您可以使用 Module#prepend。而不是include,您可以prepend 一个模块,这样模块的所有方法都将覆盖任何现有的具有相同名称的类实例方法。你可以看一个简单的例子here。

    在 Ruby 2 之前,Rails 引入了类似的 hack:#alias_method_chain

    Here 很好地比较了这两种方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-19
      • 1970-01-01
      • 1970-01-01
      • 2011-05-27
      相关资源
      最近更新 更多