作为对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_方法不包含“foo”。原因在http://ruby-doc.org/core/classes/Module.src/M001652.html
使用remove_method告诉我Helpers没有“foo”方法,所以我想我需要某种方法从祖先链中删除第一个包含…
这个过程有点长,所以我不再在结尾处放这么多代码片段,但是我添加了一个irb会话,显示了undef/remove的行为,然后是include。

最佳答案

不能只取消定义那些不会被覆盖的方法吗?

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

(将首先搜索后一个包含的模块,以便如果betterformhelpers也定义了oldformhelpers方法,则不会执行该方法。)
但是,如果要动态覆盖oldformhelpers模块的其他方法,则问题仍然存在。

09-11 19:16
查看更多