如何反转ruby的include函数

Gle*_*min 22 ruby metaprogramming class

我将在代码中解释我正在寻找的内容,因为这可能是最简洁的:

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
Run Code Online (Sandbox Code Playgroud)

我曾尝试使用remove_const取消定义Mixin模块,但这似乎对Whatever没有任何影响.我曾假设#include只是将模块的引用添加到类的方法解析链中 - 但这种行为与此不一致.

任何人都可以告诉我幕后实际做了什么,以及如何扭转这种局面?

Rom*_*lez 5

因为看起来你可能想要在实例而不是整个类上完成这些,所以我会稍微改变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
Run Code Online (Sandbox Code Playgroud)

正如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
Run Code Online (Sandbox Code Playgroud)


klo*_*ner 3

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 #< C:0x11b0d90>

Run Code Online (Sandbox Code Playgroud)

  • 我投反对票。这是一种糟糕的技术,不应该使用。您甚至不从“#included_modules”数组中删除该模块,并且存在丢失方法的风险。这个问题可能没有好的答案。 (6认同)
  • 如果在包含模块“Mod”之前,类“C”中已经存在同名方法,不会有问题吗? (3认同)