是否可以在类中反转包含的模块?

时间:2009-06-19 18:43:26

标签: ruby-on-rails ruby

您可以在类中包含模块,以便在将类方法和实例方法添加到特定类的方面扩展类功能。

module M
 def self.class_method_from_module
  'from class_method_from_module'
 end

 def instance_method_from_module
  'from instance_method_from_module'
 end
end

class C
 include M

 def self.class_method
  'from class_method'
 end

 def instance_method
  'from instance_method'
 end
end

puts C.class_method => 'from class_method'

puts C.class_method_from_module => 'from class_method_from_module'

puts C.new.instance_method => 'from instance_method'

puts C.new.instance_method_from_module => 'instance_method_from_module'

现在,即使从内存中删除模块M,也可以使用以下内容:

Object.send(:remove_const, :M) #remove the module M

puts C.class_method_from_module => 'from class_method_from_module'

puts C.new.instance_method_from_module => 'instance_method_from_module'

而不是方法丢失。这是为什么?删除模块添加到类的功能的最佳方法是什么?

2 个答案:

答案 0 :(得分:9)

细节因实现而异,但我知道至少在JRuby和MRI 1.8中有一个名为Include Class的构造,当扩展或包含Module时,该构造插入到类的继承链中。因此,模块不会被垃圾收集,因为Include类仍然引用它,并且方法仍将在您的类中。 Patrick Farley就his blog中的这个及相关主题撰写了一些很棒的文章。

因此,要“移除”一个模块,可以单独取消定义来自该模块的每个方法,但这是一个非常难以实现的机制。如果使用gem是可以接受的,那么最好使用Mixology,它是专门为动态添加和删除模块而设计的。

答案 1 :(得分:5)

当您在类中包含mixin时,您实际上是将模块中定义的方法添加到类中,或者将类中的方法替换为模块中具有相同名称的方法。该类与模块没有任何关系,这就是为什么“取消定义”M模块不会影响类C的原因。所做的就是阻止你在M之外混淆。

您可以使用undef_method从类C中删除方法,但这可能会产生副作用 - 如果通过包含模块覆盖某个方法,则无法获取原始方法,例如。取消定义类方法有点难看。

C.send(:undef_method, :instance_method_from_module)
class << C
  self
end.send(:undef_method, :class_method_from_module)