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

如何反转ruby的include函数

  •  21
  • Glenjamin  · 技术社区  · 16 年前

    module Mixin
      def method
        puts "Foo"
      end
    end
    
    class Whatever
      include Mixin
    end
    
    w = Whatever.new
    w.method
    => "Foo"
    
    # some magic here
    w2 = Whatever.new
    w.method
    => NoMethodError
    

    有谁能告诉我include在幕后到底做了什么,以及如何扭转这种局面?

    4 回复  |  直到 16 年前
        1
  •  3
  •   klochner    16 年前
    module Mod
      def foo
        puts "fooing"
      end
    end
    
    class C
      include Mod
      def self.remove_module(m)
        m.instance_methods.each{|m| undef_method(m)}
      end
    end
    
    >> c = C.new
    >> c.foo
    fooing
    >> C.remove_module(Mod)
    => ["foo"]
    >> c.foo
    NoMethodError: undefined method `foo' for #&lt C:0x11b0d90>
    
    
        2
  •  5
  •   Roman Gonzalez    16 年前

    因为您可能希望在实例上而不是在整个类上完成这些操作,所以我将稍微修改klochner的代码,使其只处理一个实例,而不是一个类的所有实例。

    module ModuleRemover
    
        def remove_module(mod, options = {})
          metaclass = class << self; self end
          mod.instance_methods.each {|method_name| metaclass.class_eval { undef_method(method_name.to_sym) }}
        end
    
    end
    

    正如Mladen指出的,避免删除在宿主类上覆盖的方法是很酷的,因此 [only, exclude] 这种方法的选择将是理想的。

    >> c1 = C.new
    >> c1.foo
    => fooing
    >> c1.extend(ModuleRemover)
    >> c1.remove_module(Mod)
    >> c1.foo
    => NoMethodError: undefined method `foo' for #< C:0x11b0d90>
    >> c2 = C.new
    >> c2.foo
    => fooing
    
        3
  •  3
  •   ghoppe    16 年前

    include 要添加实例方法,您要做的是使用 extend

    More information on the difference between include and extend

        4
  •  0
  •   j.p.    16 年前

    几年前我用过宝石 evil un 相反(仅在我的旧ruby 1.8.7上)。如广告所示,工作良好:

    说明:

    如果您将“some magic here”(安装un后)替换为

    require 'un'
    Whatever.uninclude Mixin
    

    如果有人在Ruby1.9或jruby上尝试并报告结果,那就太好了(我在社区wiki上对此进行了解答)。

    推荐文章