2011年12月27日火曜日

Railsのソースを読んでみる#4 modelの生成部分

今回みるのはrailtiesの「rails/commands.rb」なのだ。

これは受け取ったコマンドに応じたcase文がつらつらと続いているのだけれど、
まずは「rails g model User name:string email:string」とした場合を想定してみましょう。

コマンドにg(generate)を指定した場合はcommands.rbの28行目の

28 require "rails/commands/#{command}"

が実行されて「rails/commands/generate」が読み込まれます。
で、そのgenerate.rbの中身が以下の通り。

1 require 'rails/generators'
2 require 'active_support/core_ext/object/inclusion'
3
4 Rails::Generators.configure!
5
6 if ARGV.first.in?([nil, "-h", "--help"])
7 Rails::Generators.help 'generate'
8 exit
9 end
10
11 name = ARGV.shift
12 Rails::Generators.invoke name, ARGV, :behavior => :invoke, :destination_root => Rails.root

これだけ。
先の例で言うと11行目で変数nameに「model」が格納された状態で
Rails::Generators.invoke が呼び出されています。
そのメソッドの在処は1つ上の階層の「rails/generators.rb」です。

164 def self.invoke(namespace, args=ARGV, config={})
165 names = namespace.to_s.split(':')
166 if klass = find_by_namespace(names.pop, names.any? && names.join(':'))
167 args << "--help" if args.empty? && klass.arguments.any? { |a| a.required? }
168 klass.start(args, config)
169 else
170 puts "Could not find generator #{namespace}."
171 end
172 end

166行目でfind_by_namespace("model")で呼び出します。
この呼び出しの結果、「Rails::Generators::ModelGenerator」が帰ってきます。
というわけで168行目にて「Rails::Generators::ModelGenerator」のstartを呼んでいます。
このstartメソッドはどこにあるのだろうか、というわけで「rails console」を立ち上げて聞いてみましょう。

require 'rails/generators'
require 'rails/generators/rails/model/model_generators'
Rails::Generators::ModelGenerator.ancestors

上記を実行するとこんな結果が返ってきます。

[Rails::Generators::ModelGenerator, Rails::Generators::NamedBase, Rails::Generators::Base, Rails::Generators::Actions, Thor::Actions, Thor::Group, Thor::Shell, Thor::Invocation, Thor::Base, Object, PP::ObjectMixin, ActiveSupport::Dependencies::Loadable, JSON::Ext::Generator::GeneratorMethods::Object, Kernel, BasicObject]

今いるrailtiesの中ではgrepしても該当のstartメソッドが無さそうなので「Thor」と呼ばれるモジュールにありそうです。
そもそも「Thor」とは何ぞや。
次回はそこら辺りを調べてみましょう。

0 件のコメント:

コメントを投稿