Rails rails generate 的执行过程

doun · 2013年01月06日 · 最后由 geniousli 回复于 2017年07月18日 · 3317 次阅读

执行命令 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 的事了

1 楼 已删除

能再有续篇吗?讲的完整些

需要 登录 后方可回复, 如果你还没有账号请 注册新账号