执行命令 rails g controller ctl_name,实际执行的顺序如下: lib/rails/commands/generate:
root = defined?(ENGINE_ROOT) ? ENGINE_ROOT : Rails.root
Rails::Generators.invoke name, ARGV, :behavior => :invoke, :destination_root => root
调用:
def self.invoke(namespace, args=ARGV, config={})
names = namespace.to_s.split(':')
if klass = find_by_namespace(names.pop, names.any? && names.join(':'))
args << "--help" if args.empty? && klass.arguments.any? { |a| a.required? }
klass.start(args, config)
else
puts "Could not find generator #{namespace}."
end
end
实际是 thor\base.rb 的 start:
def start(given_args=ARGV, config={})
config[:shell] ||= Thor::Base.shell.new
dispatch(nil, given_args.dup, nil, config)
rescue Thor::Error => e
ENV["THOR_DEBUG"] == "1" ? (raise e) : config[:shell].error(e.message)
exit(1) if exit_on_failure?
rescue Errno::EPIPE
# This happens if a thor task is piped to something like `head`,
# which closes the pipe when it's done reading. This will also
# mean that if the pipe is closed, further unnecessary
# computation will not occur.
exit(0)
end
来到 thor\group.rb 的 dispatch:
def dispatch(task, given_args, given_opts, config) #:nodoc:
if Thor::HELP_MAPPINGS.include?(given_args.first)
help(config[:shell])
return
end
args, opts = Thor::Options.split(given_args)
opts = given_opts || opts
instance = new(args, opts, config)
yield instance if block_given?
args = instance.args
if task
instance.invoke_task(all_tasks[task])
else
instance.invoke_all
end
end
此处的 dispatch 是类方法,new 其实调用了 thor\base.rb 中的没太多用的 initialize,生成了 generator 的实例,然后调用实例方法的 invoke_all,代码在 thor\invocations.rb 中:
def invoke_all #:nodoc:
self.class.all_tasks.map { |_, task| invoke_task(task) }
end
all_tasks 在 thor\base.rb 中实现:
def all_tasks
@all_tasks ||= from_superclass(:all_tasks, Thor::CoreExt::OrderedHash.new)
@all_tasks.merge(tasks)
end
其实是通过 thor\base.rb 中的 method_added 添加的:
def method_added(meth)
meth = meth.to_s
if meth == "initialize"
initialize_added
return
end
# Return if it's not a public instance method
return unless public_instance_methods.include?(meth) ||
public_instance_methods.include?(meth.to_sym)
return if @no_tasks || !create_task(meth)
is_thor_reserved_word?(meth, :task)
Thor::Base.register_klass_file(self)
end
实际的 create_task 在 group.rb 中:
def create_task(meth) #:nodoc:
tasks[meth.to_s] = Thor::Task.new(meth, nil, nil, nil, nil)
true
end
以后就是 Thor::Task 的事了