代码之家  ›  专栏  ›  技术社区  ›  Glenjamin

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

  •  5
  • Glenjamin  · 技术社区  · 14 年前

    作为后续行动 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
    

    但是,在包括 更好的助手 ,Helpers.instance_方法不包含“foo”。原因在 http://ruby-doc.org/core/classes/Module.src/M001652.html

    使用 remove_method 告诉我 Helpers 没有“foo”方法,所以我想我需要一些方法从祖先链中删除第一个包含。。。

    这个过程有点长,所以我不再在结尾处放这么多代码片段,但是我添加了一个irb会话,显示了undef/remove的行为,然后是include。

    1 回复  |  直到 7 年前
        1
  •  2
  •   crispy    14 年前

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

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

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

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