我可以从模块覆盖实例方法吗?

时间:2014-02-11 13:15:52

标签: ruby overwrite

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

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'

是否可以使用实例方法?

3 个答案:

答案 0 :(得分:2)

您可以执行以下操作:

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

答案 1 :(得分:1)

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

当你这样做时

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

<< Foo指向主环境中Foo的单例类,因为class << 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

答案 2 :(得分:1)

如果您使用的是Ruby&gt; 2.0.0然后您可以使用的是Module#prepend。代替include,您可以prepend一个模块,并且所有模块的方法都覆盖任何具有相同名称的现有类实例方法。您可以看到一个简单的示例here

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

Here对两种方法进行了很好的比较。