Ruby 通过在模块中混合重写类的实例方法

Ruby 通过在模块中混合重写类的实例方法,ruby,module,overriding,mixins,Ruby,Module,Overriding,Mixins,给定一个类a和一个模块B,混合B的实例方法,以便覆盖a的相应实例方法 module B def method1 "B\#method1" end def method2 "B\#method2" end end class A def method1 "A\#method1" end def method2 "A\#method2" end # include B does not override instanc

给定一个类a和一个模块B,混合B的实例方法,以便覆盖a的相应实例方法

module B
  def method1
    "B\#method1"
  end

  def method2
    "B\#method2"
  end
end

class A
  def method1
    "A\#method1"
  end

  def method2
    "A\#method2"
  end

  # include B    does not override instance methods!
  #              (module gets mixed into the superclass)
end

puts A.new.method1   # want it to print out "B#method1"
puts A.new.method2   # want it to print out "B#method2"
将模块
M
作为类
C
的超类插入。因此,您不能在
M
中重写
C
的方法,相反:
C
的方法重写
M
的方法。(从技术上讲,Ruby并没有使
M
成为
C
的超类,而是创建了一个不可见的Include类
⟦M′⟧
的方法表和常量表指向
M
的方法表和常量表,并使该类成为超类,但这种区别对于这个特定问题并不重要。)

在Ruby 2.0中,有一种新方法,顾名思义,它将
M
前置到
C
的祖先,换句话说,使
M
成为
C
的子类


因此,简而言之:您不能,至少现在还不能。

您可以在包含
B
之前,从
A
中删除
B
的每个方法

class A
  def method1
    "A\#method1"
  end

  def method2
    "A\#method2"
  end

  B.instance_methods(false).each { |method|
    remove_method(method) if instance_methods(false).include?(method)
  }
  include B
end
或者从
B
中:

module B
  def method1
    "B\#method1"
  end

  def method2
    "B\#method2"
  end

  def self.append_features(mod)
    instance_methods(false).each { |method|
      mod.send(:remove_method, method) if mod.instance_methods(false).include?(method)
    }
    super
  end
end

规定您不能显式地交换方法(例如,您不能直接引用“method1”或“method2”),这就是我要找的,但无法找到如何做!谢谢更好的方法可能是使用B类中包含的(基本)回调。使用另一个示例更新了答案,以从
B
中删除
A
的方法。好吧,您可以通过一些黑客操作来完成(请参阅Stefan的答案),但很高兴知道Ruby正在添加这个,因为它派上了用场。@JoeV:你问过覆盖,我想这包括不破坏
super
@Stefan的回答只是删除了这些方法,没有重写,因此,由于不再存在超类方法,因此无法将功能委托给超类方法。现在我们已经远远超过了2.0,对于那些处在我这个位置的人来说,这应该是一个公认的答案,他们想知道如果将模块
M
包含在类
D
中会发生什么,该类继承自类
C
,答案是模块
M
中的方法覆盖
C
中的方法,但正如这个答案所指出的,不是
D
中的方法