A library of utility services and concerns.
A Mixin implements recursive inheritance of both class and instance methods.
require 'sleeping_king_studios/tools/toolbox/mixin'
module Widgets
extend SleepingKingStudios::Tools::Toolbox::Mixin
module ClassMethods
def widget_types
%w[gadget doohickey thingamabob]
end
end
def widget?(widget_type)
self.class.widget_types.include?(widget_type)
end
end
The class reference for SleepingKingStudios::Tools::Toolbox::Mixin can be found in Reference.
To define a mixin, create a new Module and extend it with Mixin:
module Widgets
extend SleepingKingStudios::Tools::Toolbox::Mixin
end
Because our mixin starts with a Module, we don’t need to do anything special to define instance methods.
module Widgets
extend SleepingKingStudios::Tools::Toolbox::Mixin
def widget?(widget_type)
self.class.widget_types.include?(widget_type)
end
end
In the above example, our #widget? instance method will be automatically available to any class in which we have included our Widget mixin.
Defining class methods requires an additional step, defining a ClassMethods module inside the mixin.
module Widgets
extend SleepingKingStudios::Tools::Toolbox::Mixin
module ClassMethods
def widget_types
%w[gadget doohickey thingamabob]
end
end
end
When we include Widgets in a class or module, then Widgets::ClassMethods will be included in that class or module’s singleton class, allowing us to use the .widget_types class method.
Once the mixin is defined, simply include it in a Class or Module like any other module.
class StemBolt
include Widgets
end
StemBolt.widget_types
#=> ['gadget', 'doohickey', 'thingamabob']
StemBolt.new.widget?('gadget')
#=> true
As you can see, our instance methods are inherited from Widget, and our class methods are inherited from Widget::ClassMethods.
Mixin also supports inheritance using Module.prepend.
Mixins can also be composed together, and Mixin defines special behavior when included in another Mixin. When you include a Mixin in another Mixin, instead of defining the class methods on the intermediate mixin, the class method are merged together and will be extended onto the final class or module.
module WidgetBuilding
extend SleepingKingStudios::Tools::Toolbox::Mixin
include Widgets
module ClassMethods
def build(widget_type)
{ widget_type: }
end
end
end
class GadgetFactory
include WidgetBuilding
end
GadgetFactory.build('gadget')
#=> { widget_type: 'gadget' }
GadgetFactory.widget_types
#=> ['gadget', 'doohickey', 'thingamabob']
GadgetFactory.new.widget?('doohickey')
#=> true
In our above example, our .widget_types class method is extended onto GadgetFactory, not the intermediate mixin WidgetBuilding.
Warning: This feature can cause unexpected behavior. When you need to extend class methods onto a
Mixinmodule, use a traditional.includedhook instead of anotherMixin.
Back to Documentation