With most of my code becoming more and more stateless and functional, I haven’t given up leveraging Ruby’s excellent way of defining declarative APIs and DSL. Ruby is just too good at that.
However, I am missing a crucial tool in Ruby: being able to pass dynamic arguments to the inheritance, exactly the way I can pass arguments to the object constructor. In short, here’s what I would love to have.
class Memo::Render < Render, engine: Render::JSON property :title property :body end
Render class could then use those additional arguments in its
inherited hook, acting as an
initialize on the class level.
class Render def self.inherited(subclass, options) super subclass.engine = options[:engine] end # def self.property(name); end # def self.engine=(name); end end
This would also work for anonymous classes, of course.
Memo::Render = Class.new( Render, engine: Render::JSON)
Looks very Ruby-esque, doesn’t it?
The Problem with inherited
Currently, you need to set class variables in the inherited class to configure it.
class Memo::Render < Render def self.engine Render::JSON end end
The massive drawback here (a design flaw in Ruby?) is that this override is evaluated too late, after the
inherited hook is called. Check out the exemplary
inherited method in the superclass
Render and how it behaves.
class Render def self.engine; end def self.inherited(subclass) puts subclass #=> Memo::Render puts subclass.engine #=> nil !!! end end
As you can see, even though
engine, it isn’t evaluated at
inherited time, making this hook more or less useless if you want to cleanly initialize and setup a subclass at compile-time.
One solution could be the proposed extension of the hook, however, the complexity of this change is completely unknown to me due to my lack of Ruby core participation.