Subclassing a core Ruby class such as Hash

I need a class that acts like a hash, although not necessarily with all hash methods. I read that you should not subclass core classes like Hash. Is this true, what is the best practice for this kind of thing?

# (a) subclass Hash, add new methods and instance variables class Book < Hash def reindex @index = ..... end end # (b) create a new class from scratch, containing a hash, # and define needed methods for the contained hash class Book def initialize(hash) @data = hash end def []=(k,v) @data[k] = v end # etc.... def reindex @index = .... end # (c) like (b) but using method_missing # (d) like (b) but using delegation 

I understand that Ruby has several ways to do the job, but are there any general rules for which of the above methods is preferable in a relatively simple case?

+4
source share
1 answer

If I absolutely do not want the Hash-like object to have specific hash methods, I would wrap the object in my class and only expose the methods that I want it to have (your option b).

If I wanted it to retain its true hash behavior with some added behavior, I would add this behavior in the module to the hash object itself without changing the hash class class:

 module SpecialHash def reindex # method def end end my_hash = {} my_hash.extend(SpecialHash) my_hash.reindex #now is defined on my hash 

More often than not, one of these options will do the trick for me.

In general, I prefer to use modules to extend the behavior of a class instead of class inheritance, because I find it cleaner and easier. Creating a new class always gives me the feeling that I am adding a new β€œthing” to my domain model. That's great, and exactly what you want to do in countless scenarios, but the Ruby mixin features give you a very nice alternative when you don't need to go that far.

The main time when I am creating a class is if there is some additional state in the object that I want to track. If my additions do not concern the extension of the state of an object, but simply extend its behavior, then I will almost always start by mixing this behavior with an existing instance of this class using a module.

Another answer to this question also brings up some other points to keep in mind: ruby inheritance vs mixins

+10
source

All Articles