Recently we stumbled upon this inheritance issue, which seemed very weird at the first:
class A def talk 'A' end end class B < A def self.define_talk define_method :talk do super() << 'B' end end end class C < B define_talk def talk super << 'C' end end > C.new.talk => "AC"
The talk addition from class B doesn’t appear, even though define_talk is triggered by Class C. C’s super call seems to ignore its direct parent B.
Overriding vs Overwriting
The reason for that is the delayed execution of define_talk, which adds the talk method to C rather than B. The previous definition of C is equivalent to this:
class C < B # calling define_talk is equivalent to def talk super << 'B' end def talk super << 'C' end end
The second definition of talk doesn’t override the first one, it overwrites it: The first definition is completely gone and therefore no longer available as super.
Overriding with Anonymous Modules
To fix this we need to ensure that B defines the method on B or another untouched inheritance layer. This layer can be an anonymous module created and included by the define_talk method:
class B < A def self.define_talk mod = Module.new do define_method :talk do super() << 'B' end end include mod end end
Now C’s definition of talk only overrides the one of the anonymous module, which is therefore still available as super.
> C.new.talk => "ABC"