Go to list of users who liked
More than 5 years have passed since last update.
環境
- ruby 2.1.1p76
- Rails 4.1.1
railsコマンド
ふとrails new
した時の流れが気になったので・・・
まずはrailsコマンドの在処を調べて、ファイルの中身を確認します。
$which rails/Users/usutani/.rvm/gems/ruby-2.1.1@rails411/bin/rails$cat`which rails`
ファイル先頭のコメント部を確認すると・・・
# !/usr/bin/env ruby_executable_hooks## このファイルはRubyGemsによって生成されました。## アプリケーションrailtiesはgemの一部としてインストールされ、# このファイルはその実行を容易にするためここにあります。#
とのこと。ファイルの続きは・・・
require'rubygems'version=">= 0"ifARGV.firststr=ARGV.firststr=str.dup.force_encoding("BINARY")ifstr.respond_to?:force_encodingifstr=~/\A_(.*)_\z/andGem::Version.correct?($1)thenversion=$1ARGV.shiftendendgem'railties',versionloadGem.bin_path('railties','rails',version)
if文のブロックでrails _4.1.1_ new
のように第一引数にバージョンが指定された場合に対応する。
指定したバージョンのrailtiesが無ければGem::LoadErrorで終了する。
最後に、バージョンを指定してrailtiesのrailsをロードする。requireでないのは二度目以降も読み込むため。
バージョンを指定しない場合の振る舞いをirbで試してみると・・・
>gem'railties',">= 0"=>true>loadGem.bin_path('railties','rails',">= 0")Usage:railsnewAPP_PATH[options]...>Gem.bin_path('railties','rails',">= 0")=>"/Users/usutani/.rvm/gems/ruby-2.1.1@rails411/gems/railties-4.1.1/bin/rails"
ロードしているrailtiesのbinディレクトリに存在するrailsファイルの中身を確認します。
# !/usr/bin/env rubygit_path=File.expand_path('../../../.git',__FILE__)ifFile.exist?(git_path)railties_path=File.expand_path('../../lib',__FILE__)$:.unshift(railties_path)endrequire"rails/cli"
railtiesディレクトリの上位に.git ディレクトリが存在すれば、自身を優先してロードされるように探索パス$:(組み込み変数)にlibを追加してから、rails/cliをロードしています。
railties/lib
cli.rb
require'rails/app_rails_loader'# アプリのrailsコマンドで実行した場合は、残りのスクリプトは実行されません。Rails::AppRailsLoader.exec_app_rails
今はアプリ外のrailsコマンドを実行しているので、残り(下記)のスクリプトが実行されます。
require'rails/ruby_version_check'Signal.trap("INT"){puts;exit(1)}ifARGV.first=='plugin'ARGV.shiftrequire'rails/commands/plugin'elserequire'rails/commands/application'end
Ctrl + Cが押されたら、プログラムを異常終了する。rails new
の場合なので、else節に入りrails/commands/applicationがロードされる。
Generators
続けてrails/commands/application.rbを確認します。
require'rails/generators'require'rails/generators/rails/app/app_generator'moduleRailsmoduleGeneratorsclassAppGenerator# :nodoc:# We want to exit on failure to be kind to other libraries# This is only when accessing via CLIdefself.exit_on_failure?trueendendendendargs=Rails::Generators::ARGVScrubber.new(ARGV).prepare!Rails::Generators::AppGenerator.startargs
Generatorは、Rails 3.0からThorをベースにしています。
exit_on_failure?をオーバライドして、失敗時に異常終了させる。
引数を準備して、Generators::AppGeneratorを開始する。
app_generator.rbの外観は次のようになります:
require'rails/generators/app_base'moduleRailsmoduleActionMethods# :nodoc:...# application builderはapplication generatorの要素を上書きできます。## Gemfile、READMEやJavaScriptファイルの作成のなどのように、あなたは全体の操作を上書きでき# ます。これらの操作を正確に把握していなくても、別のテンプレートアクションを作成できます。classAppBuilder...moduleGenerators...classAppGenerator<AppBase# :nodoc:...# このクラスはAppGeneratorが呼ばれる前に引数を準備します。このクラスはバージョンやヘルプ情# 報を求められれば提供し、(追加の設定オプションに用いる)railsrcファイルも構成します。## このクラスはARGVを設定し正しく変化させるため、AppGeneratorの開始前に、このクラスを呼び# 出す必要があります。classARGVScrubber# :nodoc...defprepare!
AppBuilder
このクラスのメソッドで、アプリ内のディレクトリ作成やファイルのコピーなどを行っています。
AppGenerator
AppBuilderとの関係が気になるので調べてみると、get_builder_classメソッドからAppBuilderを呼び出していました。
moduleGenerators...classAppGenerator<AppBase# :nodoc:...defget_builder_classdefined?(::AppBuilder)?::AppBuilder:Rails::AppBuilderend
このget_builder_classを呼んでいるのは、親クラスAppBaseです。
moduleRailsmoduleGeneratorsclassAppBase<Base# :nodoc:...protected...defbuilder@builder||=beginbuilder_class=get_builder_classbuilder_class.send(:include,ActionMethods)builder_class.new(self)endend
これらの関係を図示すると次のようになります:
Thor::Groupを派生したAppGeneratorクラスは、定義されたメソッドを順番に実行していきます。
defcreate_root_filesdefcreate_app_filesdefcreate_bin_filesdefcreate_config_filesdefcreate_boot_filedefcreate_active_record_files...
create_root_filesメソッド内のbuildの呼び出しに注目してみると、
defcreate_root_filesbuild(:readme)...
buildはAppBaseで定義されていて、builder=AppBuilderのreadmeを呼んでいます。
defbuild(meth,*args)builder.send(meth,*args)ifbuilder.respond_to?(meth)end
classAppBuilder...defreadmecopy_file"README.rdoc","README.rdoc"end
Register as a new user and use Qiita more conveniently
- You get articles that match your needs
- You can efficiently read back useful information
- You can use dark theme