I’m writing a framework for querying the Mediawiki API. I have a Page class which represents articles on the wiki, and I’ve also got a Category class, which is-a Page with more specific methods (like being able to count the number of members in the category. I’ve also got a method Page#category? which determines if an instantiated Page object is actually representative of a Mediawiki category page, by querying the API to determine the namespace of the article.
class Page
def initialize(title)
# do initialization stuff
end
def category?
# query the API to get the namespace of the page and then...
namespace == CATEGORY_NAMESPACE
end
end
class Category < Page
# ...
end
What I would like to do is be able to detect if the user of my framework tries to instantiate a Mediawiki category using a Page object (ie. Page.new("Category:My Category")), and if so, instantiate a Category object, instead of a Page object, directly from the Page constructor.
It seems to me that this should be possible because it’s reminiscent of single table inheritance in Rails, but I’m not sure how to go about getting it to work.
Ok, couple of things:
You can’t convert an instance of a class
Ato an instance ofA‘s subclassB. At least, not automatically.Bcan (and usually does) contain attributes not present inA, it can have completely different constructor etc. So, AFAIK, no OO language will allow you to “convert” classes that way.Even in static-typed languages, when you instantiate
B, and then assign it to a variableaof typeA, it is still instance ofB, it is not converted to its ancestor class whatsoever.Ruby is a dynamic language with powerful reflection capabilities, so you can always decide which class to instantiate in the runtime – check this out:
So, no need for any conversion here – just instantiate the class you need in the first place.
Another thing: as I mentioned in the comment, method
category?is simply wrong, as it violates OOP principles. In Ruby, you can – and should – use methodis_a?, so your check will look like:This is just a tip of the iceberg, there’s lot more about instantiating different classes, and another question I have linked in the comment can be a great starting point, although some code examples there might confuse you. But it is definitely worth understanding them.
Edit: After re-reading your updated question, it seems to me that the right way for you would be to create a factory class and let it do the detecting and instantiating different page types. So, user wouldn’t call
Page.newdirectly, but rather call something likeand
get_pagemethod would instantiate corresponding class.