LoginSignup
3
4

More than 5 years have passed since last update.

Railsを使わずConcernだけ使う方法と、いい感じにモジュールが読み込まれてる仕組みを調べてみた

Posted at

Railsを使わずにConcernだけ使う方法を調べていたところ、特定のクラスの名前空間以下にモジュールを作っている方法も気になったので調べてみました。

サンプルコード

Railsを使わずにActiveSupportだけでConcernを使うコードは以下です。

path_to/container.rb
require 'active_support'

ActiveSupport::Dependencies.autoload_paths << File.dirname(__FILE__)

class Container
  include Container::Feature
end

Container.new.instance_feature #=> "Instance features are loaded!"
Container.class_feature #=> "Class features are loaded!"
path_to/container/feature.rb
module Container::Feature
  extend ActiveSupport::Concern

  included do
    def instance_feature
      p 'Instance features are loaded!'
    end
  end

  class_methods do
    def class_feature
      p 'Class features are loaded!'
    end
  end
end

Railsを使っている時と違い、autoload_pathsに対象のディレクトリが自動で入ってないことでハマりました・・。

ここからContainer::Featureという形で名前空間の中に入れたままConcernを使っている時の感覚で別ファイルで書こうとすると以下の理由で困りました。

  • モジュールをincludeする際にContainer::Featureが定義されておらずエラーになる
    (uninitialized constant Container::Feature (NameError)が起きる)
  • 先にContainer::Featureモジュールを定義するとContainerクラスの名前空間がなくてエラーになる
     (uninitialized constant Container (NameError)が起きる)
    • 先にContainerというモジュールを定義して名前空間を作ろうとするとクラス名と被ってエラーになる

ActiveSupportではconst_missingをオーバライドすることでこれらの問題を解決してくれていました。

ちなみにこれをActiveSupportを使わずに同じ動作をする状態にするなら以下のようになります。

class Container
  module Feature
    def self.included base
      base.extend ClassMethods
    end

    def instance_feature
      p 'Instance features are loaded!'
    end

    module ClassMethods
      def class_feature
        p 'Class features are loaded!'
      end
    end
  end

  include Feature
end

Container.new.instance_feature #=> "Instance features are loaded!"
Container.class_feature #=> "Class features are loaded!"

参考

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4