获取包含模块的类的列表
我有一个 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 #=> #<MyClass ...>
> MyModule.classes #=> ["MyClass"]
现在,我想将这部分提取到一个单独的模块中,该模块可以包含在我的其他 mixin 中。所以,我想出了以下方法:
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 #=> #<MyClass ...>
# ^^ THIS SHOULD BE ADDING MyClass TO MyModule.classes ^^
> MyModule.classes #=> nil
我缺少什么?
I have a mixin for which I would like to get a list of all the classes that have included it. In the mixin module, I did the following:
module MyModule
def self.included(base)
@classes ||= []
@classes << base.name
end
def self.classes
@classes
end
end
class MyClass
include MyModule
end
This works pretty well:
> MyModule.classes #=> nil
> MyClass.new #=> #<MyClass ...>
> MyModule.classes #=> ["MyClass"]
Now, I would like to extract this part out into a separate module that can be included in my other mixins. So, I came up with the following:
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
This doesn't work though, because the #included(module_base) method being added to MyModule from ListIncludedClasses is never getting run. Interestingly enough, it does successfully add #classes to MyModule.
> MyModule.classes #=>
"...adding Rateable to ListIncludedClasses.classes"
=> nil
> ListIncludedClasses #=> ["MyModule"]
> MyClass.new #=> #<MyClass ...>
# ^^ THIS SHOULD BE ADDING MyClass TO MyModule.classes ^^
> MyModule.classes #=> nil
What am I missing?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
请参阅 ObjectSpace::
每个_对象。
See ObjectSpace::
each_object.
对 Cary 的答案(这太棒了!)的一个警告是,它只会选择已经由虚拟机评估过的类。
因此,如果您在开发 Rails 控制台等设置中运行该代码,则需要在检查该模块是否已包含之前显式
require
您感兴趣的文件。你可以这样做:
One caveat to Cary's answer (which is great!) is that it will only pick up on classes that have already been evaluated by the VM.
So, if you're running that code in a setting like a development Rails console you'll need to explicitly
require
the files you're interested in before checking if the module has been included.You can do that like this:
实际上,您的模块扩展模块可以工作。问题出在您的测试中:当您使用
Class.new
创建随机未命名类时,您忘记包含MyModule
。附带说明一下,您可以为包含该模块的类使用只读访问器,并使用有用的Module#attr_reader
方法。Actually, your module extension module works. The problem is in your test: when you created a random unnamed class with
Class.new
, you forgot to includeMyModule
. As a side note, you can take your read-only accessor for classes that include the module and use the helpfulModule#attr_reader
method.您可能应该使用扩展而不是包含,因为前者添加了类级别方法,而后者添加了实例级别方法(为什么您可以访问
@classes
)。试试这个:
You probably should use extend instead of include since former adds class level methods, while latter - instance level methods (why you have access to
@classes
).Try this: