rails3.2.8の起動を追いかける
プログラムコードを、スーパーpre記法できれいに書けたものの、行数をつける方法がわからない・・・とりあえず一旦諦めます。。orz
さて、本題。
railsアプリケーションの起動中、どんな流れでプログラムが実行されているのかを追ってみました。Railsのバージョンは3.2.8です。
下記のように実行したあと、サーバの起動が完了するまでの流れをざっくりと追いかけて行きたいと思います。
$ rails new sample $ cd sample $ rails s
rubyやrails等のインストールディレクトリは環境によって異なりますので、適宜読み替えて下さい。私の環境は、Mac OS X 10.7.4で以下のようになっています。
rubyコマンド | /usr/bin/ruby |
railsコマンド | /usr/bin/rails |
gemコマンド | /usr/bin/gem |
gemライブラリ | /Library/Ruby/Gems/1.8/gems |
まずは、最初に実行するrailsコマンドの中身
/usr/bin/rails
require 'rubygems' version = ">= 0" if ARGV.first =~ /^_(.*)_$/ and Gem::Version.correct? $1 then version = $1 ARGV.shift end gem 'railties', version load Gem.bin_path('railties', 'rails', version)
1行目:
"rubygems"を読み込み。読み込まれるファイルは、「/Library/Ruby/Site/1.8/rubygems.rb」
この「rubygems.rb」の中で色々な定義やファイルが読み込まれますが、とりあえず読み飛ばします。
3行目:
使用するrailsのデフォルトバージョン。
5~8行目:
・引数の最初が"_xxx_"のような形式(文字列の両端がアンダースコア)かどうかを判断
・上記形式にマッチした場合、"$1"にマッチした文字列(アンダースコアの間の部分のみ)が格納される
・上記且つ、バージョンの記述形式にマッチしていた場合、if文の中身が実行される
(バージョン記述形式はこのファイルを参照:「/Library/Ruby/Site/1.8/rubygems/version.rb 」)
・ifの中身は、"$1"に格納されたバージョン情報を、"version"へ代入し、引数のリスト"ARGV"をshiftしてるだけ。
上記ソースコードの末尾でloadしたrailsコマンドファイルの中身
/Library/Ruby/Gems/1.8/gems/railties-3.2.8/bin/rails
if File.exists?(File.join(File.expand_path('../../..', __FILE__), '.git')) railties_path = File.expand_path('../../lib', __FILE__) $:.unshift(railties_path) end require "rails/cli"
1~4行目:
railtiesがGit管理であれば、railtiesのlibをロードパスに追加(すみません、なぜかよくわかりません・・・)
"$:"は、rubyの組み込み変数で、ロードパスが格納されています。("$LOAD_PATH"と同じ)
これは"load"や"require"がファイルをロードする時に検索するディレクトリのリストです。
cli.rbの中身
require 'rbconfig' require 'rails/script_rails_loader' Rails::ScriptRailsLoader.exec_script_rails! require 'rails/ruby_version_check' Signal.trap("INT") { puts; exit(1) } if ARGV.first == 'plugin' ARGV.shift require 'rails/commands/plugin_new' else require 'rails/commands/application' end
7行目:
「Ctrl+C」でアプリケーションが終了するようにシグナルを登録しています。
9〜14行目:
引数は"plugin"ではなく"s"なので、"rails/commands/application"ライブラリを読み込みます。
以下、"exec_script_rails!"メソッドの中身です。
def self.exec_script_rails! cwd = Dir.pwd return unless in_rails_application? || in_rails_application_subdirectory? exec RUBY, SCRIPT_RAILS, *ARGV if in_rails_application? Dir.chdir("..") do exec_script_rails! unless cwd == Dir.pwd end rescue SystemCallError # could not chdir, no problem just return end
3行目、及び4行目のif、5~7行目の再帰文では、カレントディレクトリがrailsアプリケーションディレクトリ内であるかどうかを確認しているだけです。
カレントディレクトリがrailsアプリケーション内であった場合、4行目で外部コマンド「ruby script/rails s」が実行されます。
sample/script/railsの中身
次に実行されるのは、sampleアプリケーション内にある、「script/rails」ファイルです。
APP_PATH = File.expand_path('../../config/application', __FILE__) require File.expand_path('../../config/boot', __FILE__) require 'rails/commands'
1行目:
定数APP_PATHに、「config/application.rb」のパスを格納しています。
2行目:
「config/boot.rb」を読み込んでいます。あとで中身を確認します。
3行目:
"rails/commands"の読み込み。詳細は飛ばしたいとことですが、ここでスクリプトの流れが止まってしまっています。"rails/commands"の中で色々やっているのでしょう。
以下、「config/boot.rb」の中身。
require 'rubygems' # Set up gems listed in the Gemfile. ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
bundlerでgemファイルを管理している場合、ここでセットアップしてくれるようです。
ちょっと長くなりすぎてしまうので、次回「rails/commands」以降の流れを追っていきたいと思います。