3 月 04 2008

Rails::Initializer ロードパス系の処理を見る

Published by haga at 0:22 under ruby, ruby on rails, 日記

Rails::Initializerまだまだ続くよ

processメソッドで呼ばれるメソッドで

  • set_load_path
  • require_frameworks
  • set_autoload_paths
  • add_plugin_load_paths
  • load_environment

名前からして全部ロード系ですから、一気に行きますよ。

set_load_path

def set_load_path
  load_paths = configuration.load_paths + configuration.framework_paths
  load_paths.reverse_each { |dir| $LOAD_PATH.unshift(dir) if File.directory?(dir) }
  $LOAD_PATH.uniq!
end


configrationで設定したロードパスとフレームワークパスの配列を結合して、$LOAD_PATHにディレクトリかどうかのチェックと、ユニークのチェックをして追加しています。

require_frameworks

def require_frameworks
  configuration.frameworks.each { |framework| require(framework.to_s) }
rescue LoadError => e
  # re-raise because Mongrel would swallow it
  raise e.to_s
end


Configration#frameworksで指定されているフレームワークを読み込みます。 読み込みに失敗した場合、Mongrelでは「飲み込まれる」らしいのでもう一度エラーをraiseしています。

set_autoload_paths

# Set the paths from which Rails will automatically load source files, and
# the load_once paths.
def set_autoload_paths
  Dependencies.load_paths = configuration.load_paths.uniq
  Dependencies.load_once_paths = configuration.load_once_paths.uniq

  extra = Dependencies.load_once_paths - Dependencies.load_paths
  unless extra.empty?
    abort <<-end_error
      load_once_paths must be a subset of the load_paths.
      Extra items in load_once_paths: #{extra * ','}
    end_error
  end

  # Freeze the arrays so future modifications will fail rather than do nothing mysteriously
  configuration.load_once_paths.freeze
end


いきなり登場したDependencies。名前からして「依存」を表すモジュールなんでしょう。 ドキュメントも特にありませんので、今のところ無視します。

configurationのロードパスと、一度だけロードするパスをDependenciesにコピーしています。 load_pathsにload_once_pathsに加えるべきパスがあった場合は強制終了。 configuration.load_once_pathsもfreezeで凍結しています。

add_plugin_load_paths

# Adds all load paths from plugins to the global set of load paths, so that
# code from plugins can be required (explicitly or automatically via Dependencies).
def add_plugin_load_paths
  plugin_loader.add_plugin_load_paths
end

# 中略

def plugin_loader
  @plugin_loader ||= configuration.plugin_loader.new(self)
end


読みにくくなってきたなぁ。 ちょっと割愛させてもらいますが、 configuration.plugin_loaderはPlugin::Loaderを指しています(デフォルトで)。 Plugin::Loaderがどこにあるのかは、ちょっとわからなかったです。 とにかくプラグインのパスをロードパスに追加していると・・。

load_environment

# Loads the environment specified by Configuration#environment_path, which
# is typically one of development, test, or production.
def load_environment
  silence_warnings do
    return if @environment_loaded
    @environment_loaded = true
   
    config = configuration
    constants = self.class.constants
   
    eval(IO.read(configuration.environment_path), binding, configuration.environment_path)
   
    (self.class.constants - constants).each do |const|
      Object.const_set(const, self.class.const_get(const))
    end
  end
end


なんかすげー書き方してますね・・。わかりづらすぎて憎しみすら覚えます。 指定されたenvironmentファイルを読むと。productionとかdevelopmentとかtestとかの例のアレを読み込む処理がここという事ですね。今日読む中では一番親しみ深い部分かもしれませんね、書き方以外は。

silence_warningsはrails apiで検索すると、ActiveSupportでKernelにたいして拡張されたメソッドだという事がわかります。 警告を出さずにブロックを実行するためのメソッドのようです。

self.class.constantsはトップオブジェクトが持つ定数を配列で返します。

eval式を使ってconfiguration.environment_pathの内容("#{root_path}/config/environments/#{environment}.rb")をRuby式として評価する前と後で、トップオブジェクトが持つ定数の差をeachで回してObjectに定数を代入している。 って、正直よくわかんないです。次回もうちっと踏み込んでみよう。

実際のソースにトレースを仕込んで挙動を確認したりしないと、もう無理だな・・。

参考

http://d.hatena.ne.jp/walf443/20060707/rails_initializer
http://rubyist.g.hatena.ne.jp/muscovyduck/20060528/p1
http://d.hatena.ne.jp/rubyco/20060311/constants

Trackback URI | Comments RSS

Leave a Reply