Как включить модуль в другой модуль (Refactor AASM code и пользовательские состояния в модуль)

Я пытаюсь реорганизовать модель суперфата, которая имеет довольно много строк кода ActsAsStateMachine, связанных с состояниями и переходами, и я надеялся реорганизовать это на вызов модуля 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

А затем в модели

include CallStates

Мой вопрос касается включения модуля в модуль таким образом, чтобы один модуль мог быть включен в модель. Я пробовал class_eval делать тоже безрезультатно. Спасибо за любые проницательные мысли, которые вы имеете по этому поводу.

Ответ 1

Вы не можете включить один модуль в другой точно, но вы можете сказать модулю о включении других модулей в класс, в который он включался:

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

Лучше всего сделать это, только если Bmodule - это данные, необходимые для функционирования Amodule, иначе это может привести к путанице, поскольку оно явно не включено в MyClass.

Ответ 2

Вы включаете модуль в другой модуль... включая модуль в другой модуль, конечно!

module Bmodule
  def greet
    puts 'hello world'
  end
end

module Amodule
  include Bmodule
end

class MyClass
  include Amodule
end

MyClass.new.greet # => hello world

Ответ 3

Рельсы

Для Rails вам нужно сделать что-то вроде этого:

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 включается в ModuleB, который затем включается в класс MyModel.

Ответ 4

Мне нравится этот синтаксис лучший:

module Bmodule
  def greet
    puts 'hello world'
  end
end

module Amodule
  def self.included(receiver)
    receiver.send :include, Bmodule
  end
end

class MyClass
  include Amodule
end

MyClass.new.greet # => hello world