ActiveSupportはrailsの開発に役立つAPIを提供しているモジュールですが、その中にあるlazy_load_hooksという遅延処理に関連するモジュールについての記事です。
はじめに
ちまたに公開されてるgemを読んでいると、ActiveSupport.on_load :scope という記述をよく見かけます。対象スコープとなるモジュールが読み込まれた後でblockに渡した処理を遅延実行できる便利なものという認識です。
ですがいざ自分でgemを作ろうと思ったときに、on_loadで使えるスコープってどうなってるのかわからなかったので調べました、railsについてもう少し詳しく知りたい人や自分でgemを公開したい人向けかもしれません。
active_support/lazy_load_hooksについて
下記2つのインスタンス変数と3つのdefで読み込み、実行管理をしています。
- @load_hooks
- @loaded
- def self.on_load
- def self.execute_hook
- def self.run_load_hooks
run_load_hooksにて@loadedにkey,valueで対象スコープとそれに対応するnameを登録、on_loadedにて@load_hooksにて対象スコープnameと実行処理を登録します。on_loadでは対象スコープが@loadedに存在すれば即時実行、そうでなければrun_load_hooksにて@loadedに対象スコープが追加された後に、@load_hooksにスタックされた処理が遅延実行となります。
対象スコープ
最低限のrails生態系周りで登録されているスコープは以下の通り。
ActiveSupport.run_load_hooks(:action_view, self)
ActiveSupport.run_load_hooks(:active_job, self)
ActiveSupport.run_load_hooks(:active_record, Base)
ActiveSupport.run_load_hooks(:action_controller, self)
ActiveSupport.run_load_hooks(:action_mailer, self)
ActiveSupport.run_load_hooks(:i18n)
ActiveSupport.run_load_hooks(:web_console, self)
# First configurable block to run. Called before any initializers are run.
def before_configuration(&block)
ActiveSupport.on_load(:before_configuration, yield: true, &block)
end
# Third configurable block to run. Does not run if +config.cache_classes+
# set to false.
def before_eager_load(&block)
ActiveSupport.on_load(:before_eager_load, yield: true, &block)
end
# Second configurable block to run. Called before frameworks initialize.
def before_initialize(&block)
ActiveSupport.on_load(:before_initialize, yield: true, &block)
end
# Last configurable block to run. Called after frameworks initialize.
def after_initialize(&block)
ActiveSupport.on_load(:after_initialize, yield: true, &block)
end
対象スコープとなるオブジェクトの実行順
最後に参考までに上記オブジェクトのrun_load_hooks実行順です、lazy_load_hooksに直にnameを出力する記述を差し込みrails sしただけです。
- :i18n
- :active_record
- :action_view
- :web_console
- :before_configuration
- :before_initialize
- :before_eager_load
- :after_initialize
- :action_mailer
:action_controllerと:active_jobは別途controllerとjobが実行されるタイミングで動きます。
以上
以上になります。