提交 e592ee20 编写于 作者: K Kasper Timm Hansen

[ci skip] Update initialization guide samples.

Rewrite bits and pieces to mention the command infrastructure.
上级 1bf6acb1
......@@ -74,7 +74,7 @@ This file is as follows:
```ruby
#!/usr/bin/env ruby
APP_PATH = File.expand_path('../../config/application', __FILE__)
APP_PATH = File.expand_path('../config/application', __dir__)
require_relative '../config/boot'
require 'rails/commands'
```
......@@ -86,7 +86,7 @@ The `APP_PATH` constant will be used later in `rails/commands`. The `config/boot
`config/boot.rb` contains:
```ruby
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
require 'bundler/setup' # Set up gems listed in the Gemfile.
```
......@@ -131,7 +131,7 @@ Once `config/boot.rb` has finished, the next file that is required is
`ARGV` array simply contains `server` which will be passed over:
```ruby
ARGV << '--help' if ARGV.empty?
require "rails/command"
aliases = {
"g" => "generate",
......@@ -146,33 +146,37 @@ aliases = {
command = ARGV.shift
command = aliases[command] || command
require 'rails/commands/commands_tasks'
Rails::CommandsTasks.new(ARGV).run_command!(command)
Rails::Command.invoke command, ARGV
```
TIP: As you can see, an empty ARGV list will make Rails show the help
snippet.
If we had used `s` rather than `server`, Rails would have used the `aliases`
defined here to find the matching command.
### `rails/commands/commands_tasks.rb`
### `rails/command.rb`
When one types a valid Rails command, `run_command!` a method of the same name
is called. If Rails doesn't recognize the command, it tries to run a Rake task
of the same name.
When one types a Rails command, `invoke` tries to lookup a command for the given
namespace and executing the command if found.
```ruby
COMMAND_WHITELIST = %w(plugin generate destroy console server dbconsole application runner new version help)
If Rails doesn't recognize the command, it hands the reins over to Rake
to run a task of the same name.
def run_command!(command)
command = parse_command(command)
As shown, `Rails::Command` displays the help output automatically if the `args`
are empty.
if COMMAND_WHITELIST.include?(command)
send(command)
else
run_rake_task(command)
```ruby
module Rails::Command
class << self
def invoke(namespace, args = [], **config)
namespace = namespace.to_s
namespace = "help" if namespace.blank? || Thor::HELP_MAPPINGS.include?(namespace)
namespace = "version" if %w( -v --version ).include? namespace
if command = find_by_namespace(namespace)
command.perform(namespace, args, config)
else
find_by_namespace("rake").perform(namespace, args, config)
end
end
end
end
```
......@@ -180,53 +184,39 @@ end
With the `server` command, Rails will further run the following code:
```ruby
def set_application_directory!
Dir.chdir(File.expand_path('../../', APP_PATH)) unless File.exist?(File.expand_path("config.ru"))
end
def server
set_application_directory!
require_command!("server")
Rails::Server.new.tap do |server|
# We need to require application after the server sets environment,
# otherwise the --environment option given to the server won't propagate.
require APP_PATH
Dir.chdir(Rails.application.root)
server.start
module Rails
module Command
class ServerCommand < Base # :nodoc:
def perform
set_application_directory!
Rails::Server.new.tap do |server|
# Require application after server sets environment to propagate
# the --environment option.
require APP_PATH
Dir.chdir(Rails.application.root)
server.start
end
end
end
end
end
def require_command!(command)
require "rails/commands/#{command}"
end
```
This file will change into the Rails root directory (a path two directories up
from `APP_PATH` which points at `config/application.rb`), but only if the
`config.ru` file isn't found. This then requires `rails/commands/server` which
sets up the `Rails::Server` class.
```ruby
require 'fileutils'
require 'optparse'
require 'action_dispatch'
require 'rails'
module Rails
class Server < ::Rack::Server
```
`fileutils` and `optparse` are standard Ruby libraries which provide helper functions for working with files and parsing options.
`config.ru` file isn't found. This then starts up the `Rails::Server` class.
### `actionpack/lib/action_dispatch.rb`
Action Dispatch is the routing component of the Rails framework.
It adds functionality like routing, session, and common middlewares.
### `rails/commands/server.rb`
### `rails/commands/server/server_command.rb`
The `Rails::Server` class is defined in this file by inheriting from `Rack::Server`. When `Rails::Server.new` is called, this calls the `initialize` method in `rails/commands/server.rb`:
The `Rails::Server` class is defined in this file by inheriting from
`Rack::Server`. When `Rails::Server.new` is called, this calls the `initialize`
method in `rails/commands/server/server_command.rb`:
```ruby
def initialize(*)
......@@ -252,7 +242,10 @@ end
In this case, `options` will be `nil` so nothing happens in this method.
After `super` has finished in `Rack::Server`, we jump back to `rails/commands/server.rb`. At this point, `set_environment` is called within the context of the `Rails::Server` object and this method doesn't appear to do much at first glance:
After `super` has finished in `Rack::Server`, we jump back to
`rails/commands/server/server_command.rb`. At this point, `set_environment`
is called within the context of the `Rails::Server` object and this method
doesn't appear to do much at first glance:
```ruby
def set_environment
......@@ -289,17 +282,15 @@ With the `default_options` set to this:
```ruby
def default_options
environment = ENV['RACK_ENV'] || 'development'
default_host = environment == 'development' ? 'localhost' : '0.0.0.0'
{
:environment => environment,
:pid => nil,
:Port => 9292,
:Host => default_host,
:AccessLog => [],
:config => "config.ru"
}
super.merge(
Port: ENV.fetch("PORT", 3000).to_i,
Host: ENV.fetch("HOST", "localhost").dup,
DoNotReverseLookup: true,
environment: (ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development").dup,
daemonize: false,
caching: nil,
pid: Options::DEFAULT_PID_PATH,
restart_cmd: restart_command)
end
```
......@@ -311,22 +302,25 @@ def opt_parser
end
```
The class **is** defined in `Rack::Server`, but is overwritten in `Rails::Server` to take different arguments. Its `parse!` method begins like this:
The class **is** defined in `Rack::Server`, but is overwritten in
`Rails::Server` to take different arguments. Its `parse!` method looks
like this:
```ruby
def parse!(args)
args, options = args.dup, {}
opt_parser = OptionParser.new do |opts|
opts.banner = "Usage: rails server [puma, thin, etc] [options]"
opts.on("-p", "--port=port", Integer,
"Runs Rails on the specified port.", "Default: 3000") { |v| options[:Port] = v }
...
option_parser(options).parse! args
options[:log_stdout] = options[:daemonize].blank? && (options[:environment] || Rails.env) == "development"
options[:server] = args.shift
options
end
```
This method will set up keys for the `options` which Rails will then be
able to use to determine how its server should run. After `initialize`
has finished, we jump back into `rails/server` where `APP_PATH` (which was
has finished, we jump back into the server command where `APP_PATH` (which was
set earlier) is required.
### `config/application`
......@@ -345,6 +339,7 @@ def start
print_boot_information
trap(:INT) { exit }
create_tmp_directories
setup_dev_caching
log_to_stdout if options[:log_stdout]
super
......@@ -352,7 +347,6 @@ def start
end
private
def print_boot_information
...
puts "=> Run `rails server -h` for more startup options"
......@@ -364,21 +358,30 @@ private
end
end
def setup_dev_caching
if options[:environment] == "development"
Rails::DevCaching.enable_by_argument(options[:caching])
end
end
def log_to_stdout
wrapped_app # touch the app so the logger is set up
console = ActiveSupport::Logger.new($stdout)
console = ActiveSupport::Logger.new(STDOUT)
console.formatter = Rails.logger.formatter
console.level = Rails.logger.level
Rails.logger.extend(ActiveSupport::Logger.broadcast(console))
unless ActiveSupport::Logger.logger_outputs_to?(Rails.logger, STDOUT)
Rails.logger.extend(ActiveSupport::Logger.broadcast(console))
end
end
```
This is where the first output of the Rails initialization happens. This method
creates a trap for `INT` signals, so if you `CTRL-C` the server, it will exit the
process. As we can see from the code here, it will create the `tmp/cache`,
`tmp/pids`, and `tmp/sockets` directories. It then calls `wrapped_app` which is
`tmp/pids`, and `tmp/sockets` directories. It then enables caching in development
if `rails server` is called with `--dev-caching`. Finally, it calls `wrapped_app` which is
responsible for creating the Rack app, before creating and assigning an instance
of `ActiveSupport::Logger`.
......@@ -538,7 +541,7 @@ require "rails"
sprockets/railtie
).each do |railtie|
begin
require "#{railtie}"
require railtie
rescue LoadError
end
end
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册