Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I include a Module into another Module (Refactor AASM code and custom states into Module)

I'm trying to refactor a superfat model which has quite a few lines of ActsAsStateMachine code related to the states and transitions, and I was hoping to refactor this to a module call CallStates.

#in lib/CallStates.rb
module CallStates
    module ClassMethods
        aasm_column :status
        aasm_state :state1
        aasm_state :state2
        aasm_state :state3
    end

    def self.included(base)
        base.send(:include, AASM)
        base.extend(ClassMethods)
    end
end

And then in the model

include CallStates

My question concerns how to include Module behavior into a Module such that a single Module can be included into the model. I've tried class_eval do as well to no avail. Thanks for any insightful thoughts you have on the matter.

like image 664
Mike Avatar asked Feb 06 '11 17:02

Mike


People also ask

Can a Ruby module include another module?

A Ruby class can have only one superclass, but it can include any number of modules. These modules are called mixins. If you write a chunk of code that can add functionality to classes in general, it should go into a mixin module instead of a class.


3 Answers

You can't include one module in another exactly, but you can tell a module to include other modules in the class into which it's included:

module Bmodule
  def greet
    puts 'hello world'
  end
end

module Amodule
  def self.included klass
    klass.class_eval do
      include Bmodule
    end
  end
end

class MyClass
  include Amodule
end

MyClass.new.greet # => hello world

It's best to only do this if Bmodule is actually data that is necessary for Amodule to function, otherwise it can lead to confusion because it's not explicitly included in MyClass.

like image 50
Pan Thomakos Avatar answered Oct 19 '22 21:10

Pan Thomakos


You include a module into another module by ... including a module into another module, of course!

module Bmodule
  def greet
    puts 'hello world'
  end
end

module Amodule
  include Bmodule
end

class MyClass
  include Amodule
end

MyClass.new.greet # => hello world
like image 27
Jörg W Mittag Avatar answered Oct 19 '22 19:10

Jörg W Mittag


Rails

For Rails, you'll want to do something like this:

module_b.rb

module ModuleB
  extend ActiveSupport::Concern

  included do
    include ModuleA
  end
end

my_model.rb

class MyModel < ActiveRecord::Base

  include ModuleB

end

ModuleA is being included in ModuleB, which is then included in MyModel class.

like image 20
Joshua Pinter Avatar answered Oct 19 '22 19:10

Joshua Pinter