人気ブログランキング | 話題のタグを見る

RoR config/boot.rb Boot クラス

config/boot.rb で Rails.boot! メソッドは、VendorBoot と GemBoot という二つのブートに関するクラスのオブジェクトを、自動検出で切り替える働きをしていた。

VenderBoot と GemBoot はともに同じ Boot クラスの下位クラスだ。Boot クラスは次のように定義してある。

  class Boot
    def run
      load_initializer
      Rails::Initializer.run(:set_load_path)
    end
  end

Boot クラスには、run というメソッドがただ一つ定義されており、run は、load_initializer でRailsのパス関係の設定を行い、Rails::Initializer.run(:set_load_path) で、Railsの初期化が開始される。

VenderBoot も GemBoot も、Rails::Initializer.run(:set_load_path) の部分は同じコードを使用するので、上位クラスの Boot から導出して、load_initializer の部分をオーバーライドするだけで、それぞれの状況にカスタマイズすることができる。共通部分については下位クラスで記述する必要がないので、同じ記述を繰り返さず(DRY)、バグを避けることができる。継承のそうあるべき使い方だ。

VendorBoot クラスを理解するためには、Boot クラスと VendorBoot クラスの両方の定義を見る必要があるが、幸いこの二つのクラスの定義は非常に短い。Boot クラスは上に引用したので VendorBoot クラスの記述を引用する。

  class VendorBoot < Boot
    def load_initializer
      require "#{RAILS_ROOT}/vendor/rails/railties/lib/initializer"
      Rails::Initializer.run(:install_gem_spec_stubs)
    end
  end

VenderBoot では、load_initializer メソッドをオーバーライドしているが、それは、"#{RAILS_ROOT}/vendor/rails/railties/lib/initializer" ファイルを読み込んで展開しているだけだ。このファイルの中に、Rails を実行するための様々な設定のコードが記述されている。設定のあと、Rails::Initializer.run(:install_gem_spec_stubs)を実行することで、Rails をスタンバイの状態にすることができる。

ここでも、require をメソッドの定義の中で使用するという変わった使い方をしている。本当にそういうことができるのか試してみた。

~/Ruby$ cat test.rb
puts "hello"
~/Ruby$ irb
irb(main):001:0> def say
irb(main):002:1> require 'test'
irb(main):003:1> end
=> nil
irb(main):004:0> say
hello
=> true

できた。

このように VenderBoot の場合はアプリケーションと、Railsスタックの整合性がとれていることが初めから分かっているので、非常に簡単な記述になる。

話が前後するが、class << self の中の関数 vendor_rails? で Vendor Rails が存在しているかをチェックしているが、そのコードは次のようになる。

    def vendor_rails?
      File.exist?("#{RAILS_ROOT}/vendor/rails")
    end

つまり、単に vendor/rails ディレクトリが存在しているかどうかをチェックしているだけである。

GemBoot の場合は整合性のチェックなどでロジックが複雑になるが、それは次の記事で。少し疲れてきたし目も痛くなったのでしばらく休憩。
by tnomura9 | 2008-10-18 20:55 | Ruby | Comments(0)
<< RubyGems の調査 RoR config/boot... >>