Class Variables in Ruby are unlike class variables in many other programming variables. If you change the value of a class variable, all class variables in the inheritance chain are changed to this new value too. This is explained by Martin Fowler, right here.
The “solution” is to use class instance variables, as is explained here, by John Nunemaker. In his post, John also provides a module to have the class instance value carry over as a kind of constant to a subclass.
My own solution to have inheritable default values for class instance variables is this:
class Polygon class << self attr_writer :sides def sides @sides || 8 end end end
All subclasses of Polygon
will share the default value of 8 sides, but each subclass can also easily be given its own number of sides.
class Triangle < Polygon @sides = 3 end class Octogon < Polygon; end
This does what you'd expect:
>> Polygon.sides => 8 >> Triangle.sides => 3 >> Octogon.sides => 8
The new value for class Triangle
is not carried down the inheritance chain, though. Let's say you have a class FantasyShape
:
class FantasyShape < Triangle; end
What happens now is this:
>> Triangle.sides => 3 >> FantasyShape.sides => 8
To fix this, you'd have to override the class method sides
for FantasyShape
:
class FantasyShape < Triangle def self.sides @sides || superclass.sides end end
Or better yet, start the superclass lookup in the top of the inheritance chain:
class Polygon class << self attr_writer :sides def sides @sides || ((superclass.respond_to?('sides')) ? superclass.sides : 8) end end end
Now we can simplify the code for class FantasyShape
back to:
class FantasyShape < Triangle; end
And voilà:
>> Triangle.sides => 3 >> FantasyShape.sides => 3
Ruby rocks!