如何“替换”通过ruby include函数包含的模块

时间:2010-03-09 15:44:43

标签: ruby class metaprogramming

作为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。

1 个答案:

答案 0 :(得分:2)

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

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

(将首先搜索后面包含的模块,这样如果BetterFormHelpers也定义了它,则不会执行OldFormHelpers方法。)

但是,如果要动态覆盖OldFormHelpers模块的其他方法,问题仍然存在。