A follow up to Properties of Code: Functional Complexity
is coming. It’s much less “mathy” than its predecessor but serves as a
jumping off point for the next in the series. However, there is something
that has been nagging at me after watching some of the talks at this year’s
RailsConf. It’s a ubiquitous and seemingly trivial thing, but it bothers
the hell out of me:
For as long as I’ve been using Rails, a common idiom for plugins that extend
the functionality of
ActiveRecord::Base and other Rails classes follows:
module MyRailsExtension def self.included base base.extend ClassMethods base.send :include, InstanceMethods end module ClassMethods def my_dsl_extension # ... end end module InstanceMethods # ... end end class MyModel < ActiveRecord::Base include MyRailsExtension # ... end
I came to Ruby by way of Rails, and many of my early plugins used this
pattern. As time went on, I began doing more straight Ruby coding and
learned to embrace both
include. They send clear signals as
to how the mixed in modules will behave. Using the
obscures that for the sake of adding instance and singleton methods with
a single line. This bothers me a bit.
This pattern is so common that
ActiveSupport::Concern was added to Rails to
simplify the process:
module MyRailsExtension extend ActiveSupport::Concern included do # custom stuff end module ClassMethods def my_dsl_extension # ... end end module InstanceMethods # ... end end class MyModel include MyRailsExtension # ... end
This will automatically
extend ClassMethods and
and evaluate whatever code is put into the
included do ... end block.
This module has been in the Rails code base for about 2 years now, and it
bothers me. I get that
class MyModel include MyRailsExtension end
is more terse than
class MyOtherModel extend MyRailsExtension::ClassMethods include MyRailsExtension::InstanceMethods end
but the latter gives us details that especially helpful when we need to track down what an extension is really doing.
Given the frequency with which this idiom is used in the Rails world, I am probably voicing a minority opinion — as time goes on I find myself embracing more Rubyisms than Railsisms — but this is my self-serving blog. I’ll piss and moan on the topics I want to piss and moan about.