自動読み込みの仕組み

参考:

定数の自動読み込みと再読み込み | Rails ガイド [公式]

一般的な手順 | Rails ガイド [公式]

Rails の自動読み込みを支える技術 | SlideShare

Rails autoloading | NopeCode

クラスやモジュールの定義・オープンクラス

未定義のクラス・モジュールを定義 → 自動読み込みはトリガーされない

自動読み込みをしたクラスに対してオープンクラスを行うためには、class_evalmodule_eval を使用する。

MyEngine::Engine.class_eval do
  config.paths.add "dev", load_path: true
end

MyEngine::SomeFeatures.module_eval do
  def hoge_method; end
end

参考:

class および module キーワードの後に置かれる定数 | Rails ガイド [公式]

Reopening vs Overwriting a Class – Stack Overflow

トップレベルの定数

定義済みでない場合、自動読み込みがトリガーされる。

autoload_paths を順に探索して、命名規則に合致するファイルを探す。

名前空間における探索

絶対的な名前空間で修飾していない参照 (相対参照) で定数を参照した場合

module Admin
  class BaseController < ApplicationController
    p Module.nesting
    @@all_roles = Role.all
  end
end

定数 Role の探索は、定数 Role が参照された位置における Module.nesting に従って探索される。

[Admin::BaseController, Admin]

ネストされた名前空間で見つからなかった場合、ネストした最初のモジュールの祖先モジュールについて定数が定義されているかどうかが探索される。Module.nesting が空の場合には Object に定義された定数 (トップレベルの定数) が探索される。

参考:

名前空間 | Rails ガイド [公式]

ネストしたモジュールを書く場合の注意点 | ninoseki’s blog

How You Nest Modules Matters in Ruby | theScore Tech Blog

修飾済み定数の解決

"NameSpace::MyConstant".underscore によって、NameSpace::MyConstant が定義されていると期待されているファイルへの相対パスを返す。(拡張子は含まない)

"NameSpace::MyConstant".underscore
# => "name_space/my_constant"

autoload_paths に含まれる各パスで、.rb ファイルもしくは自動モジュールとなるディレクトリが探索される。

NameSpace.ancestors に含まれるモジュールに定数が定義されていると仮定して .rb ファイルもしくは自動モジュールが探索される。(Ruby 2.5 以降では祖先モジュールに含まれる途中の Object は飛ばされるため、トップレベルの定数は検出されない。)

参考:

修飾済み参照 | Rails ガイド [公式]

修飾済み定数を解決するアルゴリズム | Rails ガイド [公式]

ヒューリスティック

見つからない定数が、そのクラスまたはモジュールの親の名前空間にも存在しない場合、Rails はこの定数を相対参照であると仮定する。そうでない場合は修飾済み参照であると仮定する。

# qux.rb
Qux = "I'm at the root!"

# foo.rb
module Foo
end

# foo/qux.rb
module Foo
  Qux = "I'm in Foo!"
end

# foo/bar.rb
module Foo
  class Bar
    def self.print_qux
      puts Qux
    end
  end
end

Foo::Bar.print_qux は何を出力するか?

通常の Ruby で読み込みを実行した場合

# Using normal Ruby loading
> require "qux"
> require "foo"
> require "foo/qux"
> require "foo/bar"
> Foo::Bar.print_qux
I'm at the root!

トップレベルの定数 Qux が使われる。

Rails の自動読み込みの元で実行した場合

# Using Rails autoloading
> Foo::Bar.print_qux
I'm in Foo!

Foo モジュールの定数 Qux が使われる。

参考:

修飾済み参照 | Rails ガイド [公式]

ネストと修飾済み定数 | Rails ガイド [公式]

相対参照 | Rails ガイド [公式]

Rails autoloading – how it works, and when it doesn’t | Simon Coffey


concerns

参考:

Rails の自動読み込みについて – Qiita

lib ディレクトリの扱い (add_lib_to_load_path!)

参考:

add_lib_to_load_path! – rails/application.rb at v5.2.1 · rails/rails – GitHub

const_missing

参考:

require せずに勝手に読み込まれるとでも思ってるの? – Qiita

Rails の開発環境の自動再読み込みはどうやってるのか | Rubyリファレンス日記

How rails reloads your source code in development mode? | Codemancer

const_missing – rails/dependencies.rb at v5.2.1 · rails/rails – GitHub

ModuleConstMissing – rails/dependencies.rb at v5.2.1 · rails/rails – GitHub

load_missing_constant – rails/dependencies.rb at v5.2.1 · rails/rails – GitHub

const_missing (Module) – Rubyリファレンス

instance method Module#const_missing (Ruby 2.5.0)

ActiveSupport::Reloader

参考:

Rails の Reloader の仕組み | AnyType

リロード時に特定の処理を実行する | Oh My Enter!

ActiveSupport::Reloader | Ruby on Rails API [Official]

Watching files during Rails development | Robert Mosolgo

rails/reloader.rb at v5.2.2 · rails/rails – GitHub

rails/finisher.rb at v5.2.2 · rails/rails – GitHub

ActionDispatch::Reloader

参考:

Rails の Reloader の仕組み | AnyType

Rails Reloader: A Lesser Known Railtie Hook | Brandon Hilkert

ActionDispatch::Reloader | Ruby on Rails API [Official]

rails/reloader.rb at v5.2.2 · rails/rails – GitHub

Remove deprecated callbacks from ActionDispatch middlewares · rails/rails@3f2b7d6 – GitHub

コンソールで定数を再読み込みする

> reload!

参考:

console で reload! する場合の注意点 – Qiita

定数の再読み込み | Rails ガイド [公式]

reload! – Rails::ConsoleMethods | Ruby on Rails API [Official]

rails/app.rb at v5.2.3 · rails/rails – GitHub

reload!

定数の再読み込みを実行する。

ActiveSupport::Reloader.reload!

参考:

console で reload! する場合の注意点 – Qiita

定数の再読み込み | Rails ガイド [公式]

reload! – ActiveSupport::Reloader | Ruby on Rails API [Official]

Reload Class Cache on Demand – Stack Overflow

Why does code need to be reloaded in Rails 3? – Stack Overflow

reload-code

参考:

Class: Pry::Command::ReloadCode — Documentation for pry | RubyDoc.info

pry/reload_code.rb at v0.12.2 · pry/pry – GitHub

toplevel constant X referenced by A::X ワーニング

Ruby 2.5 より前のバージョンでは、String::HashHash と評価されてインタプリタが「toplevel constant Hash referenced by String::Hash」という warning を出力します。Ruby 2.5 以降では Object がスキップされるため、String::HashNameErrorraise されます。

参考:

Rails で Class がうまく読み込まれない問題と戦った話 – Qiita

修飾済み定数を解決するアルゴリズム | Rails ガイド [公式]

タグ:

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です