Chanko v2.0.2 -> v2.0.3

Chankoをv2.0.2からv2.0.3にしたので珍しく変更点を書いておく。

Chankoがファイルを読む仕組み

Chankoを使うとcontrollerとviewのインスタンスメソッドとして .invoke(unit_name, function_name) というのが呼べるようになる。 invoke(:foo, :bar) というメソッドを呼び出したとき、Chankoはまず app/units/foo をautoload対象のディレクトリとして登録する。 autoloadの機能を利用していると、Fooという未だ定義されていない定数を参照しようとしたとき、 登録されているディレクトリの中からfoo.rbという名前のファイルがないか探して読み込んでくれる。 Chankoを使っているアプリでは app/units/foo/foo.rb というファイルを置くことになっていて、 かつFooというmoduleをその中で定義しているはずなので、Fooという未だ定義されていない定数を参照しようとするとそれが読まれる。

RailsのEager Loadingの仕組み

Railsはproduction環境において、app/* というディレクトリをeager loadの対象として登録するようになっている。 production環境でRailsアプリが起動したとき (大抵はUnicornが起動した直後のタイミングですね)、 eager loadの対象として登録されているディレクトリがあると、 そのディレクトリの中にある全ての *.rb ファイルを再帰的に読み込むようになっている。 本番環境でautoloadとかモタモタやっていると顧客がどこかへいってしまうので、 Chankoのunitも当然アプリ起動時にこの仕組みに乗っかってeager loadingしたい。

v2.0.2の問題点

読み込んではいけないファイルが app/**/*.rb のパターンに含まれているとここで問題になる。 通常の構成では問題が無いけど、ことChankoを利用した開発においては、app/units/foo/ 等の中にファイルを詰め込む傾向にある。 なぜなら MVC + test + assets を1つのディレクトリの中に収めることで、 ちょっとプロトタイプを開発してみてダメだったらディレクトリごとすぐ捨てればOKということを実現したいから。 そのため app/units/foo/spec/features/foo_spec.rb なんかがあると、 このファイルがRailsアプリ起動時に読み込まれてしまうという問題があった。

v2.0.3での解決方法

「Railsはproduction環境において、app/* というディレクトリをeager loadの対象として登録するようになっている」というのを先に述べたけれど、これはRails.configuration.eager_load_pathsから参照できるようになっている。 今回は「app/units/foo/foo.rbのeager loadは行ってほしいがapp/units/foo/spec/foo_spec.rbのeager loadは避けたい」という要件なので、 まず(1)Railsのeager load対象からapp/unitsを外し、(2)更にRailsアプリ起動直後に自前でeager loadしてあげるという対応をした。 注意点が少しある。Rails.configuration.eager_load_pathsの値はRailsアプリ起動直後にfreezeされ 変更できなくなってしまうため、この値が用意されてからfreezeされるまでの間にeager load対象からapp/unitsを外すという処理を入れた。 また、このfreeze前の段階では未だmodelなどの定数を読み込んでもよい段階に入っていないため、 このタイミングで自前のeager loadを実行してしまうと、もしunit内からmodelやcontrollerを参照していた場合失敗してしまう。 今回は(1)と(2)の処理を2つに分割し、それぞれ別々の適切なタイミングで実行させることで対応した。

まとめ

めでたい。