如何在2个其他已包含的模块之间混合ruby模块?

时间:2013-04-27 12:26:40

标签: ruby module

假设存在以下代码:


module Foo
  def test(x)
    "Foo #{x}"
  end
end

module Bar
  def test(x)
    "Bar #{x} " + super
  end
end

class C
  include Foo
  include Bar
end

puts C.new.test(2)
# => "Bar 2 Foo 2"

我无法访问C类代码,也无法访问模块Foo和Bar。

我想在Foo和Bar之间加入一个模块,以便:


module Between
  def test(x)
    "Between " + super
  end
end

puts C.new.test(2)
# => "Bar 2 Between Foo 2"  

这是如何实现的?

3 个答案:

答案 0 :(得分:3)

module Bar; include Between end
class C; include Bar end
puts C.new.test(2)
#=> Bar 2 Between Foo 2

但请注意,在实践中,应避免使用这种无意义的模块杂耍。

答案 1 :(得分:2)

可以这样做,只要你有机会在处理C的定义之前运行你的代码。一旦定义,从super重新发送的顺序是固定的,所以任何第三方库不能覆盖它(如果他们的代码首先运行,你可以插入它之间),它只能添加到包含的模块列表中。编辑:不完全正确,请参阅Boris Stitnicky的回答,该回答有效地利用了前缀到子列表(而不是C类列表)来实现与下面相同的结果。

所以你可以这样做:

module Foo; end; module Bar; end; module Between; end
class C
  # The first time a module is included it goes to front of #included_modules array
  include Foo
  include Between
  include Bar
end

require 'foobarlib' # or whatever untouchable thing defines C, Foo and Bar

# Define your Between (this bit could be anywhere before it is needed)
module Between
  def test(x)
    "Between " + super
  end
end

puts C.new.test(2)
# => "Bar 2 Between Foo 2"

答案 2 :(得分:0)

你不想这样做,因为其中一个mixins在没有另一个的情况下不会工作,然后它真的没有把它作为mixin。只需为test中的class C - 函数创建一个包装器。

module Foo
  def self.test(x)
    "Foo #{x}"
  end
end

module Bar
  def self.test(x)
    "Bar #{x}"
  end
end

class C
  def test(x)
    Bar::test(x) + " " + Foo::test(x)
  end
end

puts C.new.test(2)
# => "Bar 2 Foo 2"

如果您对某些奇怪的reasson 真的想要这个,那么您的代码几乎是正确的。

module Foo
  def test(x)
    "Foo #{x}"
  end
end

module Bar
  def test(x)
    "Bar #{x} " + super(x) # <= you where missing the parameter here
  end
end

class C
  include Foo
  include Bar
end

puts C.new.test(2)
# => "Bar 2 Foo 2"