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?
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.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: