获取包含模块的类列表

我有一个mixin,我想获得包含它的所有类的列表。 在mixin模块中,我做了以下事情:

module MyModule def self.included(base) @classes ||= [] @classes << base.name end def self.classes @classes end end class MyClass include MyModule end 

这非常有效:

 > MyModule.classes #=> nil > MyClass.new #=> # > MyModule.classes #=> ["MyClass"] 

现在,我想将这部分提取到一个单独的模块中,该模块可以包含在我的其他mixins中。 所以,我想出了以下内容:

 module ListIncludedClasses def self.included(base) p "...adding #{base.name} to #{self.name}.classes" @classes ||= [] @classes << base.name base.extend(ClassMethods) end def self.classes @classes end module ClassMethods def included(module_base) p "...adding #{module_base.name} to #{self.name}.classes" @module_classes ||= [] @module_classes << module_base.name super(module_base) end def classes @module_classes end end end module MyModule include ListIncludedClasses end 

但这不起作用,因为从ListIncludedClasses添加到MyModule的#included(module_base)方法永远不会运行。 有趣的是,它确实成功地将#classes添加到MyModule。

 > MyModule.classes #=> "...adding Rateable to ListIncludedClasses.classes" => nil > ListIncludedClasses #=> ["MyModule"] > MyClass.new #=> # # ^^ THIS SHOULD BE ADDING MyClass TO MyModule.classes ^^ > MyModule.classes #=> nil 

我错过了什么?

 module MyMod; end class A; include MyMod; end class B < A; end class C; end ObjectSpace.each_object(Class).select { |c| c.included_modules.include? MyMod } #=> [B, A] 

实际上,您的模块扩展模块可以工作。 问题在于您的测试:当您使用Class.new创建一个随机的未命名类时,您忘记包含MyModule 。 作为旁注,您可以为包含该模块的类使用只读访问器,并使用有用的Module#attr_reader方法。

您可能应该使用extend而不是include,因为前者添加了类级别方法,而后者 – 实例级别方法(为什么您可以访问@classes )。

试试这个:

 module MyModule extend ListIncludedClasses::ClassMethods end