我需要这样的一些:
module One def test; puts 'Test One'; end end module Two def test; puts 'Test Two'; end end class Foo include One include Two include One end
在这种情况下,我需要“Test One”,但显然它会返回“Test Two”。我需要一个简洁的方法来重新包含我的模块。
有什么建议吗?
谢谢!
答案 0 :(得分:2)
class Module
def include_again(mod)
mod.instance_methods.each { |m|
self.send(:define_method, m) { |*args|
mod.instance_method(m).bind(self).call(*args)
}
}
end
end
module One
def test(a); puts "test one #{a}"; end
end
module Two
def test; puts "test two"; end
end
class Foo
include One
include Two
end
Foo.new.test #=> "test two"
class Foo
include_again One
end
Foo.new.test(1) #=> "test one 1"
答案 1 :(得分:0)
我不确定remove_method
以外的解决方法,但为什么你所展示的内容不起作用的原因是Ruby执行方法查找的方式。< / p>
在Foo
创建的每个步骤中检查ancestors
的{{1}}给了我们一个很大的暗示:
Foo
输出:
module One
def test; puts 'Test One'; end
end
module Two
def test; puts 'Test Two'; end
end
class Foo
include One
p ancestors
include Two
p ancestors
include One
p ancestors
end
如果一个模块已经在类的祖先中,Ruby不允许你再次重新包含它。因此,当<{em> [Foo, One, Object, Kernel]
[Foo, Two, One, Object, Kernel]
[Foo, Two, One, Object, Kernel]
之后包含<{1}}时,Two
会在One
的查找表中出现,Two
才有机会,无论您重新包含多少次Foo
。
答案 2 :(得分:0)
您可以调整include的行为:
module One
def test; puts 'Test One'; end
end
module Two
def test; puts 'Test Two'; end
end
class Foo
@mods = []
def self.include(mod)
@mods.delet mod
@mods << mod
end
def self.new(*args)
super.tap { |o| @mods.each { |m| o.extend m } }
end
include One
include Two
include One
end
答案 3 :(得分:0)
@banister,非常感谢你的回答,因为我无法发表评论我会在这里添加代码,使其与块和参数一起使用:
class Module
def include_again(mod)
mod.instance_methods.each{ |m|
self.send(:define_method, m) { |*args, &block|
mod.instance_method(m).bind(self).call(*args, &block)
}
}
end
end