【问题标题】:How can I "replace" a module included via ruby include function如何“替换”通过 ruby​​ 包含函数包含的模块
【发布时间】:2011-01-25 12:01:17
【问题描述】:

作为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”方法,所以我想我需要某种方法从祖先链中删除第一个包含...

这有点长,所以我停止在最后添加这么多的 sn-ps,但我添加了一个 irb 会话,显示 undef/remove 的行为,然后是一个 include。

【问题讨论】:

  • “这是我无权修改的代码”:猴子补丁不是一个选项吗?
  • 猴子补丁是一个选项,有点——但是我们替换的模块的工作方式,它定义模块然后包含它们——将代码注入到这个链的某个地方来阻止包括发生。虽然在追求这条线一段时间后,我开始更倾向于这个方向。

标签: ruby class metaprogramming


【解决方案1】:

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

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

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

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

【讨论】:

    猜你喜欢
    • 2013-10-28
    • 1970-01-01
    • 1970-01-01
    • 2016-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-10
    • 2011-03-30
    相关资源
    最近更新 更多