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: ActiveSupport::Concern
.
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 extend
and include
. They send clear signals as
to how the mixed in modules will behave. Using the self.included
Railsism
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 include InstanceMethods
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.