I got a Base
superclass and a bunch of derived classes, like Base::Number
, Base::Color
. I'd like to be able to use those child classes as if I they inherited from say Fixnum
in the case of Number
.
What's the best way to do this, while still having them respond appropriately to is_a? Base
?
So, I should be able to do
Number.new(5) + Number.new(6) # => 11
Number.new.is_a? Base # => true
I'm thinking I could mix-in Base, and overwrite the is_a?, kind_of? and instance_of? methods, but hopefully there's a cleaner way.
This is actually quite simple using Ruby:
module Slugish
attr_accessor :slug
def loud_slug
"#{slug}!"
end
end
class Stringy < String
include Slugish
end
class Hashy < Hash
include Slugish
end
hello = Stringy.new("Hello")
world = Stringy.new("World")
hello.slug = "So slow"
world.slug = "Worldly"
hello.loud_slug #=> "So slow!"
world.loud_slug #=> "Worldly!"
hello.is_a?(Slugish) #=> true
world.is_a?(Slugish) #=> true
"#{hello} #{world}" #=> "Hello World"
stuff = Hashy.new
stuff[:hello] = :world
stuff.slug = "My stuff"
stuff.loud_stug #=> "My stuff!"
stuff.is_a?(Slugish) #=> true
Why do you insist on using is_a?/kind_of? when respond_to? is a much cleaner way of checking things? You want objects to implement an interface/contract not to be a subclass of any arbitrarily chosen superclass. But maybe I'm missing some kind of requirement here.
Edit: I understand your reasoning, but it often leads to poor OO/dynamic design. Either you're doing something like this, which might be an acceptable idea in leaf classes but in a framework should be solved with inheritance:
if a.is_a?(something)
#do something
elif a.is_a?(something_else)
#do something else
...
or something like this:
if !a.is_a?(something)
#raise condition/return null/etc.
endif
...
I think that letting code fail with does not understand exception in message passing based language is a perfect design decision.
As an added problem, using is_a? instead of respond_to? limits your ability to use mock-up objects while unit testing. Which can be quite a big issue even for moderately complicated code.
I think you are using inheritance incorrectly if you have completely unrelated classes like "Number" and "Color" all deriving from the same base class. I would use composition instead if they do need access to the same routines (not sure why they would though).
Ruby's equivalent to multiple inheritance is mixins. It sounds to me like what you want is for Base to be a module that gets mixed in to several classes.