I want the following module to be included in a class I have:
module InheritanceEnumerator
def self.included(klass)
klass.instance_eval do
instance_variable_set('@subclasses',[])
def self.subclasses
@subclasses
end
original_method = self.respond_to?(:inherited) ? self.public_method(:inherited) : nil
instance_variable_set('@original_inherited_method', original_method)
def self.inherited(subclass)
@original_inherited_method.call(subclass) if @original_inherited_method
@subclasses<<subclass
end
end
end
end
What I'm trying to achieve is that I want my parent class to have references to direct children. I also need any other previous "inherited" methods set on my class by other stuff to stay in place. What am I doing wrong?
Your code works in this situation (for me):
class C; include InheritanceEnumerator; end
C.subclasses #=> []
class C1 < C; end
class C2 < C; end
C.subclasses #=> [C1, C2]
But fails in the following situation:
class C11 < C1; end
C1.subclasses => NoMethodError: undefined method `<<' for nil:NilClass
This is because you are only initializing @subclasses
when the module is included; but you are forgetting that subclasses of C
also have access to the modules methods but do not explictly include
it.
You fix this by doing the following:
def self.subclasses
@subclasses ||= []
@subclasses
end
def self.inherited(subclass)
@original_inherited_method.call(subclass) if @original_inherited_method
@subclasses ||= []
@subclasses << subclass
end
EDIT:
Okay, in future, please state what your problem is more fully and provide the test code you are using; as this was an exercise in frustration.
The following works fine with your code:
class C
def self.inherited(s)
puts "inherited by #{s}!"
end
include InheritanceEnumerator
end
class D < C; end #=> "inherited by D!"
C.subclasses #=> [D]
Perhaps the reason it wasn't working for you is that you included InheritanceEnumerator
before you had defined the inherited
method?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With