developmentを実現したいのでコードを読んでみる#2
昨日はRails::Applicationの継承関係をはっきりさせて、初期化のあたりをどうなっているのかRails Guideのドキュメントをみつけてわーいってところまで行きました。
Rails::Railtie <|---- Rails::Engine <|---- Rails::Application
http://guides.rubyonrails.org/initialization.html
で、本題は何だったのかっていうと、
./application.rb:168: middleware.use ::ActionDispatch::Reloader unless config.cache_classes
でございます。
初期化周りは上のドキュメントとコードをざっくり読んで分かった気になったけど、実はたぶん分かっていないことが分かってはいるけど、あえて分かったように振る舞ってみることで先に進んじゃいます。
というわけで今日は本丸 ActionDispatch::Reloader のコードを読みます。
ActionDispatch::Reloader
https://github.com/rails/rails/blob/3-1-stable/actionpack/lib/action_dispatch/middleware/reloader.rb
分かった気になっているので、誤解を恐れず書いてみるとRack::Serverを継承したRails::Serverのインスタンスがリクエストを処理する際にappをcallするのですが、そのappにはmiddlewareがわらわらとくっついていて、callの呼び出しに対してフィルタをかける感じです。
そのmiddlewareの一つが読もうとしているActionDispatch::Reloaderです。なのでcallメソッドが理解できれば良いはずなんですが、
def call(env) run_callbacks :prepare response = @app.call(env) response[2].extend(CleanupOnClose) response rescue Exception run_callbacks :cleanup raise end
最初のrun_callbacksでいきなり躓きましたwこれはきっと、includeされているActiveSupport::Callbacksで定義されているメソッドなんでしょう。
ActiveModel::Callbacksもこいつを使ってるのは知ってたのですが、ここでも出てきやがりました。ちょっとActiveSupport::Callbacksをやっつけましょう。
ActiveSupport::Callbacks
https://github.com/rails/rails/blob/3-1-stable/activesupport/lib/active_support/callbacks.rb
ソースコードを見ると結構難しいことをたくさんやっている感じなので、まずはドキュメントを見てみましょう。
http://api.rubyonrails.org/classes/ActiveSupport/Callbacks.html のExampleを見てみると、define_callbacks でコールバックのkindだけ定義して、set_callbackでコールバックのkindに対して、いつ何をするのかを登録できる。で、実際に動くときにrun_callbacksをkindを指定して実行すると、set_callbackでkindに対して登録されたコールバックが呼び出される、って感じですね。
ポイントはrun_callbackがインスタンスメソッドなのに対して、
define_callbacks と set_callback はクラスメソッドってこと。なので、上のリンク先には後者は書いてなくて、 http://api.rubyonrails.org/classes/ActiveSupport/Callbacks/ClassMethods.html
に説明が書いてあります。
ざーっと読んだ感じだと、 ActiveSupport::Callbacks.define_callbacks の :scope オプションが難しいっすね。
http://api.rubyonrails.org/classes/ActiveSupport/Callbacks/ClassMethods.html#method-i-define_callbacks
define_callbacks :save, :scope => [:kind, :name]
という風に定義されて、
set_callback :save, :before, Audit.new
という風にコールバック用のオブジェクトが指定されていたら、 Audit#before_saveメソッドが実行されると。
define_callbacks :save, :scope => [:kind]
ならAudit#beforeで
define_callbacks :save, :scope => [:name]
ならAudit#saveなんだそうですよ。
kindが before/after/aroundで、nameが指定されたdefine_callbackに指定されたcallbacksの要素ってことですね。
おっけー。じゃあ気を取り直して ActionDispatch::Reloader を読もう!と思ったけど、明日早いのでもう寝ます。また明日ー。