2010-03-09 61 views
5

包括一个模块作为How can I reverse ruby's include function的后续,这是很好的回答,但事实证明我的简化实际问题意味着解决方案不适用。如何“替换”通过红宝石包括功能

现在我碰到这样的(名称变更为保护身份!):

module OldFormHelpers 
    def foo 
    puts "foo" 
    end 
    def bar 
    puts "bar" 
    end 
end 

module Helpers 
    include OldFormHelpers 
end 

这给了我:

Helpers.instance_methods 
=> ["bar", "foo"] 
Helpers.ancestors 
=> [Helpers, OldFormHelpers] 

这是代码,我真的没有访问修改,而不分叉。

我想要做的是创建一个新模块;

module BetterFormHelpers 
    def foo 
    puts "better foo" 
    end 
end 

这需要从OldFormHelpers删除的行为,然后在新的东西从BetterFormHelpers

以前的解决方案增加了使用undef_method像这样:

Helpers.module_eval do 
    OldFormHelpers.instance_methods do |m| 
    undef_method(m) 
    end 
end 

然而,包括后BetterFormHelpers,Helpers.instance_methods不包含“foo”。这样做的原因在http://ruby-doc.org/core/classes/Module.src/M001652.html

使用remove_method告诉我,Helpers不具有“foo”的方法进行说明,所以我想我需要去除的祖先链第一包含的一些方法...

这会变得有点长,所以我停止了将这么多片段放到最后,但是我添加了一个irb会话来显示undef/remove的行为,然后添加一个include。

+0

“这是我没有真正有权修改的代码”:猴子补丁不是一个选项吗? – 2010-03-09 16:13:01

+0

猴子补丁是一个选项,有点 - 但是我们要替换的模块的工作方式,它定义了模块,然后包含它们 - 将代码注入到链中以阻止包含发生是非常棘手的。尽管在追求这条路线一段时间之后,我开始更多地朝这个方向倾斜。 – Glenjamin 2010-03-09 16:42:49

回答

2

难道你不能没有定义那些不会被覆盖的方法吗?

Helpers.module_eval do 
    (OldFormHelpers.instance_methods - BetterFormHelpers.instance_methods).each do |m| 
    undef_method(m) 
    end 
end 

(后者包括模块将首先搜索,以便如果BetterFormHelpers还限定它没有OldFormHelpers方法将被执行。)

如果要动态地覆盖OldFormHelpers模块的又一方法,但是,问题依旧。