その中の1節
「2.5.2 アプリケーションを初期化するための20の手順」
をたよりに、Railsの初期化コード(rails-version/lib/initializer.rb)を読んでみようという(
Rails のバージョンは 2.3.3です。
前置き
initializer.rb の前に、(一番初めから追ってみたかったので...)まずはエントリポイントとなる script/server を。
# script/server
#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../config/boot'
require 'commands/server'
script/serverでは、2つのファイルを require しているだけです。
1つずつ見ていきます。まずは、config/boot.rb。
# config/boot.rb (抜粋)
# Don't change this file!
# Configure your app in config/environment.rb and config/environments/*.rb
RAILS_ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(RAILS_ROOT)
module Rails
class << self
def boot!
unless booted?
preinitialize
pick_boot.run
end
end
def pick_boot
(vendor_rails? ? VendorBoot : GemBoot).new
end
end
class Boot
def run
load_initializer
Rails::Initializer.run(:set_load_path)
end
end
class VendorBoot < Boot
def load_initializer
require "#{RAILS_ROOT}/vendor/rails/railties/lib/initializer"
Rails::Initializer.run(:install_gem_spec_stubs)
Rails::GemDependency.add_frozen_gem_path
end
end
class GemBoot < Boot
def load_initializer
self.class.load_rubygems
load_rails_gem
require 'initializer'
end
end
end
# All that for this:
Rails.boot!
boot.rb は
- グローバル変数 RAILS_ROOT をセット
- Railsモジュールにboot!メソッドを追加
- Rails.boot! の呼び出し
という流れになっています。
肝となる Rails.boot! メソッドでは、pick_boot メソッドで Bootクラスインスタンスが生成され(*1)、Boot.runが呼ばれます。そして、このBoot.runの中でRails::Initializer.runが呼ばれる、という仕組み。
(*1) 実際に生成されるのはBootクラスのサブクラスであるVenderBootクラスもしくはGemBootクラスのインスタンス。vender/railsが存在する場合はVenderBoot, なければGemBootが選択される。
次に、script/server内で2つめにrequireされるcommands/server.rb。こちらはRails本体の中にあります。
# rails/commands/server.rb
~~略~~
# 71行目から
if File.exist?(options[:config])
config = options[:config]
if config =~ /\.ru$/
cfgfile = File.read(config)
if cfgfile[/^#\\(.*)/]
opts.parse!($1.split(/\s+/))
end
inner_app = eval("Rack::Builder.new {( " + cfgfile + "\n )}.to_app", nil, config)
else
require config
inner_app = Object.const_get(File.basename(config, '.rb').capitalize)
end
else
require RAILS_ROOT + "/config/environment"
inner_app = ActionController::Dispatcher.new
end
~~略~~
-c または --config オプションを指定しなければ、デフォルト環境設定ファイルの config/environment.rb がrequireされます。(ここにいたのか environment.rb)
そして、config/environment.rb の中で
# config/environment.rb
RAILS_GEM_VERSION = '2.3.3' unless defined? RAILS_GEM_VERSION
# Bootstrap the Rails environment, frameworks, and default configuration
require File.join(File.dirname(__FILE__), 'boot')
Rails::Initializer.run do |config|
# Settings in config/environments/* take precedence over those specified here.
~~略~~
end
Rails::Initializer.runが再び(今度は引数なし/ブロック付きで)呼ばれます。
# Rails::Initializer は初期化処理で2回呼ばれる・・・?
Rails::Initializer
前置きはこのぐらいにして、Rails::Initializer のコードをみてみます。
コメントとか、いろいろはしょって骨格だけ。
# rails/lib/initializer.rb
require 'logger'
require 'set'
require 'pathname'
$LOAD_PATH.unshift File.dirname(__FILE__)
require 'railties_path'
require 'rails/version'
require 'rails/plugin/locator'
require 'rails/plugin/loader'
require 'rails/gem_dependency'
require 'rails/rack'
RAILS_ENV = (ENV['RAILS_ENV'] || 'development').dup unless defined?(RAILS_ENV)
module Rails
class Initializer
def self.run(command = :process, configuration = Configuration.new)
yield configuration if block_given?
initializer = new configuration
initializer.send(command)
initializer
end
def process
Rails.configuration = configuration
check_ruby_version # (1)
install_gem_spec_stubs # (2)
set_load_path # (3)
add_gem_load_paths # (4)
require_frameworks # (5)
set_autoload_paths # (6)
add_plugin_load_paths # (7)
load_environment # (8)
preload_frameworks # (9)
initialize_encoding # (10)
initialize_database # (11)
initialize_cache # (12)
initialize_framework_caches # (13)
initialize_logger # (14)
initialize_framework_logging # (15)
initialize_dependency_mechanism # (16)
initialize_whiny_nils # (17)
initialize_time_zone # (18)
initialize_i18n # (19)
initialize_framework_settings # (20)
initialize_framework_views # (21)
initialize_metal # (22)
add_support_load_paths # (23)
check_for_unbuilt_gems # (24)
load_gems # (25)
load_plugins # (26)
add_gem_load_paths # (27)
load_gems # (28)
check_gem_dependencies # (29)
return unless gems_dependencies_loaded # (30)
load_application_initializers # (31)
after_initialize # (32)
initialize_database_middleware # (33)
prepare_dispatcher # (34)
initialize_routing # (35)
load_observers # (36)
load_view_paths # (37)
load_application_classes # (38)
disable_dependency_loading # (39)
Rails.initialized = true
end
~~略~~
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
~~略~~
end
end
(runメソッドだけ取り出してみます。)
def self.run(command = :process, configuration = Configuration.new)
yield configuration if block_given?
initializer = new configuration
initializer.send(command)
initializer
end
(1行目) メソッドシグネチャ。Initializer.runは引数を2つ(command, configuration)とります。Configurationは、同じRailsモジュール内で定義されているクラス。
(2行目) ブロックを与えると、configurationがyieldされます。
(3行目) Initializerがnewされます。いきなり new とあるのは、self.new の略記らしい。普段Javaを使っていると、new Configuration()に見えてまぎらわしい。(--;;
(4行目) commandで与えられたメソッドを呼び出します。
(5行目) Initializerをreturn(?)
前置きでみた2つのInitializer.runについて見直すと、
(1)
config/boot.rb 内での Initializer.run呼び出しは
Rails::Initializer.run(:set_load_path)
とcommand引数が与えられているため4行目は set_load_path メソッドの呼び出しとなります。
(2)
config/environment.rb 内での Initializer.run呼び出しは
Rails::Initializer.run do |config|
# settings
end
で、command引数が省略されているため4行目は processメソッド(デフォルト)の呼び出しとなります。ブロックが与えられているため、2行目のyieldも実行されます。
肝となるのは、(2)のprocessメソッドを呼び出しているほうになります。
processメソッドはすごくシンプルで、サブメソッドを順々に呼び出しているだけです(呼ばれるメソッド名を眺めるだけでも、なんとなくやっていることがわかる)。
今日はここまで。。。
次から、processメソッドで呼ばれるメソッド (1)~(39) を読んでいきたいと思います。
続く。たぶん。
----
- [Rails][CodeReading] Rails::Initializer (1) check_ruby_version
- [Rails][CodeReading] Rails::Initializer (2) install_gem_spec_stubs
- [Rails][CodeReading] Rails::Initializer (3) set_load_path
- [Rails][CodeReading] Rails::Initializer (4) add_gem_load_paths
- [Rails][CodeReading] Rails::Initializer (5) require_frameworks
- [Rails][CodeReading] Rails::Initializer (6) set_autoload_paths
- [Rails][CodeReading] Rails::Initializer (7) add_plugin_load_paths
- [Rails][CodeReading] Rails::Initializer (8) load_environment
- [Rails][CodeReading] Rails::Initializer (9) preload_frameworks
- [Rails][CodeReading] Rails::Initializer (10) initialize_encoding
- [Rails][CodeReading] Rails::Initializer (11) initialize_database
- [Rails][CodeReading] Rails::Initializer (12) initialize_cache
- [Rails][CodeReading] Rails::Initializer (13) initialize_framework_caches
- [Rails][CodeReading] Rails::Initializer (14) initialize_logger
- [Rails][CodeReading] Rails::Initializer (15) initialize_framework_logging
- [Rails][CodeReading] Rails::Initializer (16) initialize_dependency_mechanism
- [Rails][CodeReading] Rails::Initializer (17) initialize_whiny_nils
- [Rails][CodeReading] Rails::Initializer (18) initialize_time_zone
- [Rails][CodeReading] Rails::Initializer (19) initialize_i18n
- [Rails][CodeReading] Rails::Initializer (20) initialize_framework_settings
- [Rails][CodeReading] Rails::Initializer (21) initialize_framework_views
- [Rails][CodeReading] Rails::Initializer (22) initialize_metal
- [Rails][CodeReading] Rails::Initializer (23) add_support_load_paths
- [Rails][CodeReading] Rails::Initializer (24) check_for_unbuilt_gems
- [Rails][CodeReading] Rails::Initializer (25) load_gems
- [Rails][CodeReading] Rails::Initializer (26) load_plugins
- [Rails][CodeReading] Rails::Initializer (27) add_gem_load_paths
- [Rails][CodeReading] Rails::Initializer (28) load_gems
- [Rails][CodeReading] Rails::Initializer (29) (30) check_gem_dependencies
- [Rails][CodeReading] Rails::Initializer (31) load_application_initializers
- [Rails][CodeReading] Rails::Initializer (32) after_initialize
- [Rails][CodeReading] Rails::Initializer (33) initialize_database_middleware
- [Rails][CodeReading] Rails::Initializer (34) prepare_dispatcher
- [Rails][CodeReading] Rails::Initializer (35) initialize_routing
- [Rails][CodeReading] Rails::Initializer (36) load_observers
- [Rails][CodeReading] Rails::Initializer (37) load_view_paths
- [Rails][CodeReading] Rails::Initializer (38) load_application_classes
- [Rails][CodeReading] Rails::Initializer (39) disable_dependency_loading
0 件のコメント:
コメントを投稿