Gle*_*min 5 ruby metaprogramming class
作为一个跟进我如何反转ruby的包含函数,这个问题得到了很好的解答,但结果表明我对实际问题的简化并不意味着该解决方案不适用.
我现在面对这个(名称改为保护身份!):
module OldFormHelpers
def foo
puts "foo"
end
def bar
puts "bar"
end
end
module Helpers
include OldFormHelpers
end
Run Code Online (Sandbox Code Playgroud)
这给了我:
Helpers.instance_methods
=> ["bar", "foo"]
Helpers.ancestors
=> [Helpers, OldFormHelpers]
Run Code Online (Sandbox Code Playgroud)
这是我无法真正有权修改的代码,而不需要分叉.
我想要做的是创建一个新模块;
module BetterFormHelpers
def foo
puts "better foo"
end
end
Run Code Online (Sandbox Code Playgroud)
这需要从中删除行为OldFormHelpers,然后从中添加新内容BetterFormHelpers
以前的解决方案是这样使用undef_method:
Helpers.module_eval do
OldFormHelpers.instance_methods do |m|
undef_method(m)
end
end
Run Code Online (Sandbox Code Playgroud)
但是,在包含之后BetterFormHelpers,Helpers.instance_methods不包含"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
Run Code Online (Sandbox Code Playgroud)
(将首先搜索后者包含的模块,以便如果 BetterFormHelpers 也定义了 OldFormHelpers 方法,则不会执行该方法。)
但是,如果您想动态覆盖 OldFormHelpers 模块的其他方法,问题仍然相同。