rails -v で Railsのバージョンが分かる仕組み
rails --help を見てみると、-vでバージョンを表示したり、 rails hoge で hogeアプリケーションを作成したり、rails -h でヘルプを表示したりしているのですが、いったいどのようなロジックになっているのか気になったので見てみました。
% rails -v Rails 2.3.5 % rails "_1.2.3_" -v Rails 1.2.3
railsコマンドの場所を知る
% which rails
/opt/local/bin/rails
railsコマンドの内容を知る
1 #!/opt/local/bin/ruby 2 # 3 # This file was generated by RubyGems. 4 # 5 # The application 'rails' is installed as part of a gem, and 6 # this file is here to facilitate running it. 7 # 8 9 require 'rubygems' 10 11 version = ">= 0" 12 13 if ARGV.first =~ /^_(.*)_$/ and Gem::Version.correct? $1 then 14 version = $1 15 ARGV.shift 16 end 17 18 gem 'rails', version 19 load Gem.bin_path('rails', 'rails', version)
ポイントは、Gem.bin_path('rails', 'rails', version) です。rails -v と入力したとき、最初は /opt/local/bin/rails で受けるのですが、Gem.bin_path('rails', 'rails', version) で指定のバージョンのRailsをロードして、-v の引数は /opt/local/lib/ruby/gems/1.8/gems/rails-2.3.5/bin/rails に移ります。
詳しく見る
ruby の load は Ruby プログラム file をロードして実行します。Gem.bin_path は 以下のような動きをします。
/opt/local/bin% irb irb(main):001:0> Gem.bin_path('rails') => "/opt/local/lib/ruby/gems/1.8/gems/rails-2.3.5/bin/rails" irb(main):002:0> Gem.bin_path('rails', 'rails') => "/opt/local/lib/ruby/gems/1.8/gems/rails-2.3.5/bin/rails" irb(main):003:0> Gem.bin_path('rails', 'rails', '1.2.3') => "/opt/local/lib/ruby/gems/1.8/gems/rails-1.2.3/bin/rails"
つまり、railsファイルの19行目は、
load "/opt/local/lib/ruby/gems/1.8/gems/rails-2.3.5/bin/rails"
とやっていることと同じになります。
load したあと、-v が引数として評価され実行されます。
% ruby /opt/local/lib/ruby/gems/1.8/gems/rails-2.3.5/bin/rails -v Rails 2.3.5 % ruby /opt/local/lib/ruby/gems/1.8/gems/rails-1.2.3/bin/rails -v Rails 1.2.3
railsコマンド内で require 'rubygems' していますので、正確に書くと以下になります。
% ruby -rubygems /opt/local/lib/ruby/gems/1.8/gems/rails-2.3.5/bin/rails -v Rails 2.3.5
/opt/local/lib/ruby/gems/1.8/gems/rails-2.3.5/bin/rails の中身
1 require File.dirname(__FILE__) + '/../lib/ruby_version_check' 2 Signal.trap("INT") { puts; exit } 3 4 require File.dirname(__FILE__) + '/../lib/rails/version' 5 if %w(--version -v).include? ARGV.first 6 puts "Rails #{Rails::VERSION::STRING}" 7 exit(0) 8 end 9 10 freeze = ARGV.any? { |option| %w(--freeze -f).include?(option) } 11 12 app_path = ARGV.first 13 14 require File.dirname(__FILE__) + '/../lib/rails_generator' 15 16 require 'rails_generator/scripts/generate' 17 Rails::Generator::Base.use_application_sources! 18 Rails::Generator::Scripts::Generate.new.run(ARGV, :generator => 'app') 19 20 Dir.chdir(app_path) { `rake rails:freeze:gems`; puts "froze" } if freeze
上のファイルを見ると、
puts "Rails #{Rails::VERSION::STRING}"
でバージョンが表示されるのが分かりますね。
実験環境
OS | Mac OS X 10.6.2 |
RubyGemsの状態は以下です。
/Users/japanrock% gem env RubyGems Environment: - RUBYGEMS VERSION: 1.3.6 - RUBY VERSION: 1.8.7 (2010-01-10 patchlevel 249) [i686-darwin10] - INSTALLATION DIRECTORY: /opt/local/lib/ruby/gems/1.8 - RUBY EXECUTABLE: /opt/local/bin/ruby - EXECUTABLE DIRECTORY: /opt/local/bin - RUBYGEMS PLATFORMS: - ruby - x86-darwin-10 - GEM PATHS: - /opt/local/lib/ruby/gems/1.8 - /Users/japanrock/.gem/ruby/1.8 - GEM CONFIGURATION: - :update_sources => true - :verbose => true - :benchmark => false - :backtrace => false - :bulk_threshold => 1000 - REMOTE SOURCES: - http://rubygems.org/
まとめ
最近、毎日Railsのコードを少しずつ読むようにしています。感じるのはプログラマの成長を支える上で、コードリーディングは非常に有益だと思うことです。
Railsのコードリーディングはrubyのことも知れますし、もちろんrailsのことも知れます。一流の人がどのようにコードを書くのか、どのような設計をするのか、 思いつかないようなrubyの使い方など、想像力が膨らみます。
私の場合、時間を決めて(例えば 10:00〜11:00)1日1時間行うようにしています。時間が取れないようであれば、30分になったりします。だらだら伸ばしたりしません。そうして毎日続ける方が私にはあっているようです。最近は何事も習慣化するように心がけています。