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 を読もう!と思ったけど、明日早いのでもう寝ます。また明日ー。