码迷,mamicode.com
首页 > 其他好文 > 详细

rails4启动过程

时间:2015-05-03 16:06:33      阅读:207      评论:0      收藏:0      [点我收藏+]

标签:

    本篇博文会从使用rails server命令到应用启动完成的代码调用顺序,介绍rails server的启动过程,是对rails guide的一个简略翻译和一些博主的认识,翻译的不好还请各位见谅。看的时候最好找一份rails4的源码一起对照的来看。

    原文地址: http://guides.ruby-china.org/initialization.html

    当我们使用rails c(onsole)或者rails s(erver)时会启动一个rails的应用,rails s其实相当于在当前路径下执行了一段ruby脚本:

version = ">=0"
load Gem.bin_path(‘railties‘, ‘rails‘, version)

如果在Rails console里输入上面的命令,你会看到railties/bin/rails被执行了。

在railties/bin/rails源码的最后一行可以看到

require “rails/cli”

require了railties/lib/rails/cli,继续跟进,在railties/lib/rails/cli中:

require ‘rails/app_rails_loader‘
# If we are inside a Rails application this method performs an exec and thus
# the rest of this script is not run.
Rails::AppRailsLoader.exec_app_rails

继续进入railties/lib/rails/app_rails_loader.rb

RUBY = Gem.ruby
EXECUTABLES = [‘bin/rails‘, ‘script/rails‘]
......

class << self
    ......
    def exec_app_rails
      original_cwd = Dir.pwd
      loop do
        if exe = find_executable
          contents = File.read(exe)
     
          if contents =~ /(APP|ENGINE)_PATH/
            exec RUBY, exe, *ARGV
            break # non reachable, hack to be able to stub exec in the test suite
          elsif exe.end_with?(‘bin/rails‘) && contents.include?(‘This file was generated by Bundler‘)
            $stderr.puts(BUNDLER_WARNING)
            Object.const_set(:APP_PATH, File.expand_path(‘config/application‘, Dir.pwd))
            require File.expand_path(‘../boot‘, APP_PATH)
            require ‘rails/commands‘
            break
          end
        end
        # If we exhaust the search there is no executable, this could be a
        # call to generate a new application, so restore the original cwd.
        Dir.chdir(original_cwd) and return if Pathname.new(Dir.pwd).root?
       
        # Otherwise keep moving upwards in search of an executable.
        Dir.chdir(‘..‘)
      end
    end
       
    def find_executable
      EXECUTABLES.find { |exe| File.file?(exe) }
    end
end

可以通过上面的代码看出Rails::AppRailsLoader.exec_app_rails会在当前目录下找bin/rails或script/rails,找到了就会执行:

 exec Gem.ruby, bin/rails, *ARGV

即相当于

exec ruby bin/rails server

如果当前目录下没有bin/rails或script/rails就会一直递归向上直到找到bin(script)/rails,所以在rails项目的根目录以及子目录下的任何地方都可以使用rails server或rails console命令

bin/rails:

#!/usr/bin/env ruby
APP_PATH = File.expand_path(‘../../config/application‘, __FILE__)
require_relative ‘../config/boot‘
require ‘rails/commands‘

APP_PATH常量将会在之后的rails/commands里使用require_relative ‘../config/boot‘是require了config/boot.rb文件,boot.rb负责加载启动Bundler

config/boot.rb

# Set up gems listed in the Gemfile.
ENV[‘BUNDLE_GEMFILE‘] ||= File.expand_path(‘../../Gemfile‘, __FILE__)
 
require ‘bundler/setup‘ if File.exist?(ENV[‘BUNDLE_GEMFILE‘])

在标准的的Rails应用中,Gemfile文件申明了所有应用依赖关系,ENV[‘BUNDLE_GEMFILE‘]存放Gemfile的文件地址,当Gemfile文件存在,回去require bundle/setup,用于Bundler配置加载Gemfile依赖关系的路径。

一个标准的Rails应用需要依赖几个gem包,如:

  • actionmailer

  • actionpack

  • actionview

  • activemodel

  • activerecord

  • activesupport

  • arel

  • builder

  • bundler

  • erubis

  • i18n

  • mail

  • mime-types

  • polyglot

  • rack

  • rack-cache

  • rack-mount

  • rack-test

  • rails

  • railties

  • rake

  • sqlite3

  • thor

  • treetop

  • tzinfo

require了config/boot.rb后回到bin/rails,最后还会require rails/commands

rails/commands.rb

主要用于扩展rails命令参数的别名:

rails/commands.rb

ARGV << ‘--help‘ if ARGV.empty?
 
aliases = {
  "g"  => "generate",
  "d"  => "destroy",
  "c"  => "console",
  "s"  => "server",
  "db" => "dbconsole",
  "r"  => "runner"
}
 
command = ARGV.shift
command = aliases[command] || command
 
require ‘rails/commands/commands_tasks‘
 
Rails::CommandsTasks.new(ARGV).run_command!(command)

可以看到当不传参数时,实际上与rails --help等效,rails s等效于rails server

rails/commands/command_tasks.rb

当输入了一个错误的rails命令,run_command方法负责抛出一个错误信息。如果命令是有效的,就会调用相同名称的方法

COMMAND_WHITELIST = %(plugin generate destroy console server dbconsole application runner new version help)
 
def run_command!(command)
  command = parse_command(command)
  if COMMAND_WHITELIST.include?(command)
    send(command)
  else
    write_error_message(command)
  end
end

def write_error_message(command)
  puts "Error: Command ‘#{command}‘ not recognized"
  if %x{rake #{command} --dry-run 2>&1 } && $?.success?
    puts "Did you mean: `$ rake #{command}` ?\n\n"
  end
  write_help_message 
  exit(1)
end
          
def parse_command(command) 
  case command 
  when ‘--version‘, ‘-v‘ 
    ‘version‘ 
  when ‘--help‘, ‘-h‘ 
     ‘help‘
  else
     command 
  end
end


等下继续

rails4启动过程

标签:

原文地址:http://my.oschina.net/u/1413049/blog/410036

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!