Inheriting class methods from modules / mixins in Ruby
A common idiom is to use included
hook and inject class methods from there.
module Foo
def self.included base
base.send :include, InstanceMethods
base.extend ClassMethods
end
module InstanceMethods
def bar1
'bar1'
end
end
module ClassMethods
def bar2
'bar2'
end
end
end
class Test
include Foo
end
Test.new.bar1 # => "bar1"
Test.bar2 # => "bar2"
Can a ruby class method inherit from another class?
class Users::PasswordsController < Devise::PasswordsController
...
end
In the above code, Users is the module and PasswordsController is the class inside Users module. Similarly Devise is the module and PasswordsController is the class inside Devise module.
so when you run
Users::PasswordsController.class
#=> Class
Users.class
#=>Module
Ruby module inclusion with class methods and inheritance
When you do include M1
in M2
, the instance methods of M1
as well as the class methods coming from ClassMethods
are incorporated into M2
because of the self.included
definition in M1
.
But when you do include M2
in Foo
, you only include the instance methods of M2
. The class methods of M2
are not incorporated into Foo
.
ruby inheritance vs mixins
I just read about this topic in The Well-Grounded Rubyist (great book, by the way). The author does a better job of explaining than I would so I'll quote him:
No single rule or formula always results in the right design. But it’s useful to keep a
couple of considerations in mind when you’re making class-versus-module decisions:
Modules don’t have instances. It follows that entities or things are generally best
modeled in classes, and characteristics or properties of entities or things are
best encapsulated in modules. Correspondingly, as noted in section 4.1.1, class
names tend to be nouns, whereas module names are often adjectives (Stack
versus Stacklike).A class can have only one superclass, but it can mix in as many modules as it wants. If
you’re using inheritance, give priority to creating a sensible superclass/subclass
relationship. Don’t use up a class’s one and only superclass relationship to
endow the class with what might turn out to be just one of several sets of characteristics.
Summing up these rules in one example, here is what you should not do:
module Vehicle
...
class SelfPropelling
...
class Truck < SelfPropelling
include Vehicle
...
Rather, you should do this:
module SelfPropelling
...
class Vehicle
include SelfPropelling
...
class Truck < Vehicle
...
The second version models the entities and properties much more neatly. Truck
descends from Vehicle (which makes sense), whereas SelfPropelling is a characteristic of vehicles (at least, all those we care about in this model of the world)—a characteristic that is passed on to trucks by virtue of Truck being a descendant, or specialized
form, of Vehicle.
To break up Ruby class into separate files by mixins or plain definitions?
Are your support methods general enough that they might be useful for other totally unrelated classes? If so, a mixin is the proper way to do this, since it lets you easily reuse the support code.
However if your support methods are very specific to ReallyBigClass and are unlikely to work if included somewhere else, reopening the class is the way to go. Using a mixin there could give the appearance that the methods are more general than they really are, when really they should only be used with instances of a specific class.
That being said, I think your question indicates a larger design problem. If you are in the former case (general methods), you should be designing more general modules in the first place to avoid tight coupling. A module called ReallyBigClassFileB
gives off some strong code smell. In the latter case (very specific methods) if your class is so big that its file is unmanageably large you probably need to refactor something. Maybe your class is responsible for too much? Maybe it could use some subclasses (which make sense in separate files)?
Inheriting from class Module
Module
is indeed a Ruby class. An instance of the class Module
is a Ruby module. To illustrate, these two ways of defining a module are equivalent:
module MyModule
# ...
end
# is equivalent to
MyModule = Module.new do
# ...
end
If an instance of Module
is a Ruby module, that means that an instance of any subclass of Module
is also a Ruby module, including Shrine::Attachment
. This makes sense, because we know that we can include
only modules, so an instance of Shrine::Attachment
has to be a module.
Because of Shrine's plugin system design, this:
class Attachment < Module
@shrine_class = ::Shrine
end
isn't the whole implementation of Shrine::Attachment
; the actual implementation is defined in the Shrine::Plugins::Base::AttachmentMethods
module, which gets included into Shrine::Attachment
.
If we look at the implementation of Shrine::Attachment.new
, we can see that it dynamically defines methods on itself based on the given attribute name. For example, Shrine::Attachment.new(:image)
will generate a module with the following methods defined: #image_attacher
, #image=
, #image
, and #image_url
. These methods will then get added to the model that includes that Shrine::Attachment
instance.
Why didn't I just have a method that creates a new module via Module.new
(like Refile does), instead of creating a whole subclass of Module
? Well, two main reasons:
First, this gives better introspection, because instead of seeing #<Module:0x007f8183d27ab0>
in your model's ancestors list, you now see an actual Shrine::Attachment
instance that points to its definition. You could still manually override #to_s
and #inspect
, but this is better.
Second, since Shrine::Attachment
is now a class, other Shrine plugins can extend it with more behaviour. So remote_url plugin adds the #<attachment>_remote_url
accessor, data_uri plugin adds the #<attachment>_data_uri
accessor etc.
Ruby mixin class methods
I'd rewrite the module using instance methods and instance variables, i.e.:
module Mixin
def set_n(n)
@n = n
end
def get_n
@n ||= 0
end
end
The above can then be added to your class via extend
:
class Klass
extend Mixin
set_n 100
end
Klass.get_n #=> 100
Note that get_
and set_
prefixes are quite unidiomatic in Ruby. You typically use the attribute's name as the getter and append a =
for the setter.
How to mixin some class methods and some instance methods from a module in Ruby?
This pattern is very common in Ruby. So common, in fact, that ActiveSupport::Concern abstracts it a bit.
Your typical implementation looks like this:
module Foo
def self.included(other_mod)
other_mod.extend ClassMethods
end
def instance_method
end
module ClassMethods
def class_method
end
end
end
class Bar
include Foo
end
You can't accomplish this easily as you describe without somehow splitting the included module into multiple pieces, though, unfortunately.
Related Topics
Total Newbie: Instance Variables in Ruby
In Ruby on Rails, Are '#Encoding: Utf-8' and 'Config.Encoding = "Utf-8"' Different
How to Remove Lines of Data in the Middle of a Text File with Ruby
Idiomatic Object Creation in Ruby
How to Match Something With Regex That Is Not Between Two Special Characters
Gemfile.Lock Write Error, Permissions
How to Solve This Trouble to Deploy a Rails App to Heroku
Why Does White-Space Affect Ruby Function Calls
Rails - Render :Action to Target Anchor Tag
The <<- Operator on Ruby, Where Is It Documented
Reading the Last N Lines of a File in Ruby
Converting Ruby Array to Array of Consecutive Pairs
Ruby/Rails - Change the Timezone of a Time, Without Changing the Value