覆盖另一个模块的模块方法

时间:2011-02-04 16:10:48

标签: ruby

我想覆盖来自另一个模块B的模块A的方法,该方法将猴子补丁A.
http://codepad.org/LPMCuszt

module A
  def foo; puts 'A' end
end

module B
  def foo; puts 'B'; super; end
end

A.module_eval { include B } # why no override ???

class C
  include A
end

# must print 'A B', but only prints 'A' :(
C.new.foo

4 个答案:

答案 0 :(得分:6)

module A
  def foo
    puts 'A'
  end
end

module B
  def foo
    puts 'B'
    super
  end
end

include A # you need to include module A befor you can override method

A.module_eval { include B }

class C
  include A
end

C.new.foo # => B A

答案 1 :(得分:2)

包含一个模块将放在上面包含在类层次结构中的模块/类。换句话说,A#foo不是B#foo的超级,而是反过来。

如果你想将一个模块作为一种做多重继承的方法,这是有道理的,include SomeModule是一种说法,“对待SomeTodule就好像它是我的父类”。

要获得您想要的输出,您需要反转包含,以便B包含A:

module A
  def foo; puts 'A' end
end

module B
  def foo; puts 'B'; super; end
end

B.module_eval { include A } # Reversing the inclusion

class C
  include B # not include A
end

puts C.new.foo

编辑以回应评论:

然后要么在A中包括A和B,而在A:

之后包括B.
# A and B as before without including B in A.

class C
  include A
  include B
end

或在C本身补丁A,不要打扰B.

# A as before, no B.

class C
  include A

  def foo; puts 'B'; super; end
end

这种方法的唯一方法是,如果C上的方法查找是C - > B - > A并且没有将B包含在C中就无法做到这一点。

答案 2 :(得分:0)

实现此目的的另一种方法是在包含模块A时包含模块B.

module A
  def foo
    puts "this should never be called!"
    "a"
  end
end

module B
  def foo
    "b"
  end
end

module A
  def self.included(base)
    base.class_eval do
      include B
    end
  end
end

class C
  include A
end

C.new.foo # "b"

答案 3 :(得分:0)

这也是您问题的一个解决方案。我试图通过模块挂钩 included来实现。将模块A 包含到 C类中时。 模块A 中定义的包含回调被调用并执行。我们在运行中包含模块B 。所以我们的模块方法 foo 模块B foo 覆盖,以打印名为

module A
  def self.included klass
    klass.send(:include, B)
  end
  def foo
    puts 'A'
  end
 end

module B
  def foo
   super
   puts 'B'
  end
end

class C
 include A
end
C.new.foo #out put A,B