1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

correct code indendation in the initialization guide

This commit is contained in:
Vijay Dev 2011-06-05 00:58:21 +05:30
parent 087f8e16a6
commit 9f19322b1f

View file

@ -20,15 +20,15 @@ h4. +bin/rails+
The actual +rails+ command is kept in _bin/rails_ at the and goes like this:
<ruby>
#!/usr/bin/env ruby
#!/usr/bin/env ruby
begin
require "rails/cli"
rescue LoadError
railties_path = File.expand_path('../../railties/lib', __FILE__)
$:.unshift(railties_path)
require "rails/cli"
end
begin
require "rails/cli"
rescue LoadError
railties_path = File.expand_path('../../railties/lib', __FILE__)
$:.unshift(railties_path)
require "rails/cli"
end
</ruby>
This file will attempt to load +rails/cli+ and if it cannot find it then add the +railties/lib+ path to the load path (+$:+) and will then try to require it again.
@ -38,22 +38,22 @@ h4. +railites/lib/rails/cli.rb+
This file looks like this:
<ruby>
require 'rbconfig'
require 'rails/script_rails_loader'
require 'rbconfig'
require 'rails/script_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::ScriptRailsLoader.exec_script_rails!
# If we are inside a Rails application this method performs an exec and thus
# the rest of this script is not run.
Rails::ScriptRailsLoader.exec_script_rails!
require 'rails/ruby_version_check'
Signal.trap("INT") { puts; exit }
require 'rails/ruby_version_check'
Signal.trap("INT") { puts; exit }
if ARGV.first == 'plugin'
ARGV.shift
require 'rails/commands/plugin_new'
else
require 'rails/commands/application'
end
if ARGV.first == 'plugin'
ARGV.shift
require 'rails/commands/plugin_new'
else
require 'rails/commands/application'
end
</ruby>
The +rbconfig+ file here is out of Ruby's standard library and provides us with the +RbConfig+ class which contains useful information dependent on how Ruby was compiled. We'll see this in use in +railties/lib/rails/script_rails_loader+.
@ -76,46 +76,46 @@ The +rails/script_rails_loader+ file uses +RbConfig::Config+ to gather up the +b
Back in +rails/cli+, the next line is this:
<ruby>
Rails::ScriptRailsLoader.exec_script_rails!
Rails::ScriptRailsLoader.exec_script_rails!
</ruby>
This method is defined in +rails/script_rails_loader+ like this:
<ruby>
def self.exec_script_rails!
cwd = Dir.pwd
return unless in_rails_application? || in_rails_application_subdirectory?
exec RUBY, SCRIPT_RAILS, *ARGV if in_rails_application?
Dir.chdir("..") do
# Recurse in a chdir block: if the search fails we want to be sure
# the application is generated in the original working directory.
exec_script_rails! unless cwd == Dir.pwd
end
rescue SystemCallError
# could not chdir, no problem just return
def self.exec_script_rails!
cwd = Dir.pwd
return unless in_rails_application? || in_rails_application_subdirectory?
exec RUBY, SCRIPT_RAILS, *ARGV if in_rails_application?
Dir.chdir("..") do
# Recurse in a chdir block: if the search fails we want to be sure
# the application is generated in the original working directory.
exec_script_rails! unless cwd == Dir.pwd
end
rescue SystemCallError
# could not chdir, no problem just return
end
</ruby>
This method will first check if the current working directory (+cwd+) is a Rails application or is a subdirectory of one. The way to determine this is defined in the +in_rails_application?+ method like this:
<ruby>
def self.in_rails_application?
File.exists?(SCRIPT_RAILS)
end
def self.in_rails_application?
File.exists?(SCRIPT_RAILS)
end
</ruby>
The +SCRIPT_RAILS+ constant defined earlier is used here, with +File.exists?+ checking for its presence in the current directory. If this method returns +false+, then +in_rails_application_subdirectory?+ will be used:
<ruby>
def self.in_rails_application_subdirectory?(path = Pathname.new(Dir.pwd))
File.exists?(File.join(path, SCRIPT_RAILS)) || !path.root? && in_rails_application_subdirectory?(path.parent)
end
def self.in_rails_application_subdirectory?(path = Pathname.new(Dir.pwd))
File.exists?(File.join(path, SCRIPT_RAILS)) || !path.root? && in_rails_application_subdirectory?(path.parent)
end
</ruby>
This climbs the directory tree until it reaches a path which contains a +script/rails+ file. If a directory is reached which contains this file then this line will run:
<ruby>
exec RUBY, SCRIPT_RAILS, *ARGV if in_rails_application?
exec RUBY, SCRIPT_RAILS, *ARGV if in_rails_application?
</ruby>
This is effectively the same as doing +ruby script/rails [arguments]+. Where +[arguments]+ at this point in time is simply "server".
@ -125,9 +125,9 @@ h4. +script/rails+
This file looks like this:
<ruby>
APP_PATH = File.expand_path('../../config/application', __FILE__)
require File.expand_path('../../config/boot', __FILE__)
require 'rails/commands'
APP_PATH = File.expand_path('../../config/application', __FILE__)
require File.expand_path('../../config/boot', __FILE__)
require 'rails/commands'
</ruby>
The +APP_PATH+ constant here will be used later in +rails/commands+. The +config/boot+ file that +script/rails+ references is the +config/boot.rb+ file in our application which is responsible for loading Bundler and setting it up.
@ -137,19 +137,19 @@ h4. +config/boot.rb+
+config/boot.rb+ contains this:
<ruby>
require 'rubygems'
require 'rubygems'
# Set up gems listed in the Gemfile.
gemfile = File.expand_path('../../Gemfile', __FILE__)
begin
ENV['BUNDLE_GEMFILE'] = gemfile
require 'bundler'
Bundler.setup
rescue Bundler::GemNotFound => e
STDERR.puts e.message
STDERR.puts "Try running `bundle install`."
exit!
end if File.exist?(gemfile)
# Set up gems listed in the Gemfile.
gemfile = File.expand_path('../../Gemfile', __FILE__)
begin
ENV['BUNDLE_GEMFILE'] = gemfile
require 'bundler'
Bundler.setup
rescue Bundler::GemNotFound => e
STDERR.puts e.message
STDERR.puts "Try running `bundle install`."
exit!
end if File.exist?(gemfile)
</ruby>
In a standard Rails application, there's a +Gemfile+ which declares all dependencies of the application. +config/boot.rb+ sets +ENV["BUNDLE_GEMFILE"]+ to the location of this file, then requires Bundler and calls +Bundler.setup+ which adds the dependencies of the application (including all the Rails parts) to the load path, making them available for the application to load. The gems that a Rails 3.1 application depends on are as follows:
@ -186,34 +186,34 @@ h4. +rails/commands.rb+
Once +config/boot.rb+ has finished, the next file that is required is +rails/commands+ which will execute a command based on the arguments passed in. In this case, the +ARGV+ array simply contains +server+ which is extracted into the +command+ variable using these lines:
<ruby>
aliases = {
"g" => "generate",
"c" => "console",
"s" => "server",
"db" => "dbconsole"
}
aliases = {
"g" => "generate",
"c" => "console",
"s" => "server",
"db" => "dbconsole"
}
command = ARGV.shift
command = aliases[command] || command
command = ARGV.shift
command = aliases[command] || command
</ruby>
If we used <tt>s</tt> rather than +server+, Rails will use the +aliases+ defined in the file and match them to their respective commands. With the +server+ command, Rails will run this code:
<ruby>
when 'server'
# Change to the application's path if there is no config.ru file in current dir.
# This allows us to run script/rails server from other directories, but still get
# the main config.ru and properly set the tmp directory.
Dir.chdir(File.expand_path('../../', APP_PATH)) unless File.exists?(File.expand_path("config.ru"))
when 'server'
# Change to the application's path if there is no config.ru file in current dir.
# This allows us to run script/rails server from other directories, but still get
# the main config.ru and properly set the tmp directory.
Dir.chdir(File.expand_path('../../', APP_PATH)) unless File.exists?(File.expand_path("config.ru"))
require 'rails/commands/server'
Rails::Server.new.tap { |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
}
require 'rails/commands/server'
Rails::Server.new.tap { |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
}
</ruby>
This file will change into the root of the directory (a path two directories back 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 requires +action_dispatch+ and sets up the +Rails::Server+ class.
@ -239,7 +239,7 @@ The +methods.rb+ file is responsible for defining methods such as +camelize+, +u
In this file there are a lot of lines such as this inside the +ActiveSupport+ module:
<ruby>
autoload :Inflector
autoload :Inflector
</ruby>
Due to the overriding of the +autoload+ method, Ruby will know to look for this file at +activesupport/lib/active_support/inflector.rb+ when the +Inflector+ class is first referenced.
@ -263,10 +263,10 @@ h4. +rails/commands/server.rb+
The +Rails::Server+ class is defined in this file as inheriting from +Rack::Server+. When +Rails::Server.new+ is called, this calls the +initialize+ method in +rails/commands/server.rb+:
<ruby>
def initialize(*)
super
set_environment
end
def initialize(*)
super
set_environment
end
</ruby>
Firstly, +super+ is called which calls the +initialize+ method on +Rack::Server+.
@ -278,10 +278,10 @@ h4. Rack: +lib/rack/server.rb+
The +initialize+ method in +Rack::Server+ simply sets a couple of variables:
<ruby>
def initialize(options = nil)
@options = options
@app = options[:app] if options && options[:app]
end
def initialize(options = nil)
@options = options
@app = options[:app] if options && options[:app]
end
</ruby>
In this case, +options+ will be +nil+ so nothing happens in this method.
@ -289,64 +289,64 @@ 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:
<ruby>
def set_environment
ENV["RAILS_ENV"] ||= options[:environment]
end
def set_environment
ENV["RAILS_ENV"] ||= options[:environment]
end
</ruby>
In fact, the +options+ method here does quite a lot. This method is defined in +Rack::Server+ like this:
<ruby>
def options
@options ||= parse_options(ARGV)
end
def options
@options ||= parse_options(ARGV)
end
</ruby>
Then +parse_options+ is defined like this:
<ruby>
def parse_options(args)
options = default_options
def parse_options(args)
options = default_options
# Don't evaluate CGI ISINDEX parameters.
# http://hoohoo.ncsa.uiuc.edu/cgi/cl.html
args.clear if ENV.include?("REQUEST_METHOD")
# Don't evaluate CGI ISINDEX parameters.
# http://hoohoo.ncsa.uiuc.edu/cgi/cl.html
args.clear if ENV.include?("REQUEST_METHOD")
options.merge! opt_parser.parse! args
options[:config] = ::File.expand_path(options[:config])
ENV["RACK_ENV"] = options[:environment]
options
end
options.merge! opt_parser.parse! args
options[:config] = ::File.expand_path(options[:config])
ENV["RACK_ENV"] = options[:environment]
options
end
</ruby>
With the +default_options+ set to this:
<ruby>
def default_options
{
:environment => ENV['RACK_ENV'] || "development",
:pid => nil,
:Port => 9292,
:Host => "0.0.0.0",
:AccessLog => [],
:config => "config.ru"
}
end
def default_options
{
:environment => ENV['RACK_ENV'] || "development",
:pid => nil,
:Port => 9292,
:Host => "0.0.0.0",
:AccessLog => [],
:config => "config.ru"
}
end
</ruby>
There is no +REQUEST_METHOD+ key in +ENV+ so we can skip over that line. The next line merges in the options from +opt_parser+ which is defined plainly in +Rack::Server+
<ruby>
def opt_parser
Options.new
end
def opt_parser
Options.new
end
</ruby>
The class *is* defined in +Rack::Server+, but is overwritten in +Rails::Server+ to take different arguments. Its +parse!+ method begins like this:
<ruby>
def parse!(args)
args, options = args.dup, {}
def parse!(args)
args, options = args.dup, {}
opt_parser = OptionParser.new do |opts|
opts.banner = "Usage: rails server [mongrel, thin, etc] [options]"
@ -362,100 +362,101 @@ h4. +Rails::Server#start+
This method is defined like this:
<ruby>
def start
puts "=> Booting #{ActiveSupport::Inflector.demodulize(server)}"
puts "=> Rails #{Rails.version} application starting in #{Rails.env} on http://#{options[:Host]}:#{options[:Port]}"
puts "=> Call with -d to detach" unless options[:daemonize]
trap(:INT) { exit }
puts "=> Ctrl-C to shutdown server" unless options[:daemonize]
def start
puts "=> Booting #{ActiveSupport::Inflector.demodulize(server)}"
puts "=> Rails #{Rails.version} application starting in #{Rails.env} on http://#{options[:Host]}:#{options[:Port]}"
puts "=> Call with -d to detach" unless options[:daemonize]
trap(:INT) { exit }
puts "=> Ctrl-C to shutdown server" unless options[:daemonize]
#Create required tmp directories if not found
%w(cache pids sessions sockets).each do |dir_to_make|
FileUtils.mkdir_p(Rails.root.join('tmp', dir_to_make))
end
super
ensure
# The '-h' option calls exit before @options is set.
# If we call 'options' with it unset, we get double help banners.
puts 'Exiting' unless @options && options[:daemonize]
#Create required tmp directories if not found
%w(cache pids sessions sockets).each do |dir_to_make|
FileUtils.mkdir_p(Rails.root.join('tmp', dir_to_make))
end
super
ensure
# The '-h' option calls exit before @options is set.
# If we call 'options' with it unset, we get double help banners.
puts 'Exiting' unless @options && options[:daemonize]
end
</ruby>
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+, +tmp/sessions+ and +tmp/sockets+ directories if they don't already exist prior to calling +super+. The +super+ method will call +Rack::Server.start+ which begins its definition like this:
<ruby>
def start
if options[:warn]
$-w = true
end
def start
if options[:warn]
$-w = true
end
if includes = options[:include]
$LOAD_PATH.unshift(*includes)
end
if includes = options[:include]
$LOAD_PATH.unshift(*includes)
end
if library = options[:require]
require library
end
if library = options[:require]
require library
end
if options[:debug]
$DEBUG = true
require 'pp'
p options[:server]
pp wrapped_app
pp app
end
if options[:debug]
$DEBUG = true
require 'pp'
p options[:server]
pp wrapped_app
pp app
end
end
</ruby>
In a Rails application, these options are not set at all and therefore aren't used at all. The first line of code that's executed in this method is a call to this method:
<ruby>
wrapped_app
wrapped_app
</ruby>
This method calls another method:
<ruby>
@wrapped_app ||= build_app app
@wrapped_app ||= build_app app
</ruby>
Then the +app+ method here is defined like so:
<ruby>
def app
@app ||= begin
if !::File.exist? options[:config]
abort "configuration #{options[:config]} not found"
end
app, options = Rack::Builder.parse_file(self.options[:config], opt_parser)
self.options.merge! options
app
def app
@app ||= begin
if !::File.exist? options[:config]
abort "configuration #{options[:config]} not found"
end
app, options = Rack::Builder.parse_file(self.options[:config], opt_parser)
self.options.merge! options
app
end
end
</ruby>
The +options[:config]+ value defaults to +config.ru+ which contains this:
<ruby>
# This file is used by Rack-based servers to start the application.
# This file is used by Rack-based servers to start the application.
require ::File.expand_path('../config/environment', __FILE__)
run YourApp::Application
require ::File.expand_path('../config/environment', __FILE__)
run YourApp::Application
</ruby>
The +Rack::Builder.parse_file+ method here takes the content from this +config.ru+ file and parses it using this code:
<ruby>
app = eval "Rack::Builder.new {( " + cfgfile + "\n )}.to_app",
app = eval "Rack::Builder.new {( " + cfgfile + "\n )}.to_app",
TOPLEVEL_BINDING, config
</ruby>
The <ruby>initialize</ruby> method will take the block here and execute it within an instance of +Rack::Builder+. This is where the majority of the initialization process of Rails happens. The chain of events that this simple line sets off will be the focus of a large majority of this guide. The +require+ line for +config/environment.rb+ in +config.ru+ is the first to run:
<ruby>
require ::File.expand_path('../config/environment', __FILE__)
require ::File.expand_path('../config/environment', __FILE__)
</ruby>
h4. +config/environment.rb+
@ -475,7 +476,7 @@ h3. Loading Rails
The next line in +config/application.rb+ is:
<ruby>
require 'rails/all'
require 'rails/all'
</ruby>
h4. +railties/lib/rails/all.rb+
@ -483,20 +484,20 @@ h4. +railties/lib/rails/all.rb+
This file is responsible for requiring all the individual parts of Rails like so:
<ruby>
require "rails"
require "rails"
%w(
%w(
active_record
action_controller
action_mailer
active_resource
rails/test_unit
).each do |framework|
begin
require "#{framework}/railtie"
rescue LoadError
end
).each do |framework|
begin
require "#{framework}/railtie"
rescue LoadError
end
end
</ruby>
First off the line is the +rails+ require itself.
@ -518,9 +519,9 @@ h4. +active_support/core_ext/kernel/reporting.rb+
This is the first of the many Active Support core extensions that come with Rails. This one in particular defines methods in the +Kernel+ module which is mixed in to the +Object+ class so the methods are available on +main+ and can therefore be called like this:
<ruby>
silence_warnings do
# some code
end
silence_warnings do
# some code
end
</ruby>
These methods can be used to silence STDERR responses and the +silence_stream+ allows you to also silence other streams. Additionally, this mixin allows you to suppress exceptions and capture streams. For more information see the "Silencing Warnings, Streams, and Exceptions":http://guides.rubyonrails.org/active_support_core_extensions.html#silencing-warnings-streams-and-exceptions section from the Active Support Core Extensions Guide.
@ -635,14 +636,14 @@ h4. +railties/lib/rails/rack.rb+
The final file to be loaded by +railties/lib/rails/configuration.rb+ is +rails/rack+ which defines some simple autoloads:
<ruby>
module Rails
module Rack
autoload :Debugger, "rails/rack/debugger"
autoload :Logger, "rails/rack/logger"
autoload :LogTailer, "rails/rack/log_tailer"
autoload :Static, "rails/rack/static"
end
module Rails
module Rack
autoload :Debugger, "rails/rack/debugger"
autoload :Logger, "rails/rack/logger"
autoload :LogTailer, "rails/rack/log_tailer"
autoload :Static, "rails/rack/static"
end
end
</ruby>
Once this file is finished loading, then the +Rails::Configuration+ class is initialized. This completes the loading of +railties/lib/rails/configuration.rb+ and now we jump back to the loading of +railties/lib/rails/railtie.rb+, where the next file loaded is +active_support/inflector+.
@ -652,12 +653,12 @@ h4. +activesupport/lib/active_support/inflector.rb+
+active_support/inflector.rb+ requires a series of file which are responsible for setting up the basics for knowing how to pluralize and singularize words. These files are:
<ruby>
require 'active_support/inflector/inflections'
require 'active_support/inflector/transliterate'
require 'active_support/inflector/methods'
require 'active_support/inflector/inflections'
require 'active_support/inflector/transliterate'
require 'active_support/inflector/methods'
require 'active_support/inflections'
require 'active_support/core_ext/string/inflections'
require 'active_support/inflections'
require 'active_support/core_ext/string/inflections'
</ruby>
The +active_support/inflector/methods+ file has already been required by +active_support/autoload+ and so won't be loaded again here.
@ -721,22 +722,22 @@ h4. +activesupport/lib/active_support/i18n_railtie.rb+
This file is the first file that sets up configuration with these lines inside the class:
<ruby>
class Railtie < Rails::Railtie
config.i18n = ActiveSupport::OrderedOptions.new
config.i18n.railties_load_path = []
config.i18n.load_path = []
config.i18n.fallbacks = ActiveSupport::OrderedOptions.new
class Railtie < Rails::Railtie
config.i18n = ActiveSupport::OrderedOptions.new
config.i18n.railties_load_path = []
config.i18n.load_path = []
config.i18n.fallbacks = ActiveSupport::OrderedOptions.new
</ruby>
By inheriting from +Rails::Railtie+ the +Rails::Railtie#inherited+ method is called:
<ruby>
def inherited(base)
unless base.abstract_railtie?
base.send(:include, Railtie::Configurable)
subclasses << base
end
def inherited(base)
unless base.abstract_railtie?
base.send(:include, Railtie::Configurable)
subclasses << base
end
end
</ruby>
This first checks if the Railtie that's inheriting it is a component of Rails itself:
@ -763,15 +764,15 @@ end
The +config+ method used at the top of +I18n::Railtie+ is defined on +Rails::Railtie+ and is defined like this:
<ruby>
def config
@config ||= Railtie::Configuration.new
end
def config
@config ||= Railtie::Configuration.new
end
</ruby>
At this point, that +Railtie::Configuration+ constant is automatically loaded which causes the +rails/railties/configuration+ file to be loaded. The line for this is this particular line in +railties/lib/rails/railtie.rb+:
<ruby>
autoload :Configuration, "rails/railtie/configuration"
autoload :Configuration, "rails/railtie/configuration"
</ruby>
h4. +railties/lib/rails/railtie/configuration.rb+
@ -781,15 +782,15 @@ This file begins with a require out to +rails/configuration+ which has already b
This file defines the +Rails::Railtie::Configuration+ class which is responsible for providing a way to easily configure railties and it's the +initialize+ method here which is called by the +config+ method back in the +i18n_railtie.rb+ file. The methods on this object don't exist, and so are rescued by the +method_missing+ defined further down in +configuration.rb+:
<ruby>
def method_missing(name, *args, &blk)
if name.to_s =~ /=$/
@@options[$`.to_sym] = args.first
elsif @@options.key?(name)
@@options[name]
else
super
end
def method_missing(name, *args, &blk)
if name.to_s =~ /=$/
@@options[$`.to_sym] = args.first
elsif @@options.key?(name)
@@options[name]
else
super
end
end
</ruby>
So therefore when an option is referred to it simply stores the value as the key if it's used in a setter context, or retrieves it if used in a getter context. Nothing fancy going on there.
@ -799,21 +800,21 @@ h4. Back to +activesupport/lib/active_support/i18n_railtie.rb+
After the configuration method the +reloader+ method is defined, and then the first of of Railties' initializers is defined: +i18n.callbacks+.
<ruby>
initializer "i18n.callbacks" do
ActionDispatch::Reloader.to_prepare do
I18n::Railtie.reloader.execute_if_updated
end
initializer "i18n.callbacks" do
ActionDispatch::Reloader.to_prepare do
I18n::Railtie.reloader.execute_if_updated
end
end
</ruby>
The +initializer+ method (from the +Rails::Initializable+ module) here doesn't run the block, but rather stores it to be run later on:
<ruby>
def initializer(name, opts = {}, &blk)
raise ArgumentError, "A block must be passed when defining an initializer" unless blk
opts[:after] ||= initializers.last.name unless initializers.empty? || initializers.find { |i| i.name == opts[:before] }
initializers << Initializer.new(name, nil, opts, &blk)
end
def initializer(name, opts = {}, &blk)
raise ArgumentError, "A block must be passed when defining an initializer" unless blk
opts[:after] ||= initializers.last.name unless initializers.empty? || initializers.find { |i| i.name == opts[:before] }
initializers << Initializer.new(name, nil, opts, &blk)
end
</ruby>
An initializer can be configured to run before or after another initializer, which we'll see a couple of times throughout this initialization process. Anything that inherits from +Rails::Railtie+ may also make use of the +initializer+ method, something which is covered in the "Configuration guide":[http://ryanbigg.com/guides/configuring.html#rails-railtie-initializer].
@ -821,25 +822,25 @@ An initializer can be configured to run before or after another initializer, whi
The +Initializer+ class here is defined within the +Rails::Initializable+ module and its +initialize+ method is defined to just set up a couple of variables:
<ruby>
def initialize(name, context, options, &block)
@name, @context, @options, @block = name, context, options, block
end
def initialize(name, context, options, &block)
@name, @context, @options, @block = name, context, options, block
end
</ruby>
Once this +initialize+ method is finished, the object is added to the object the +initializers+ method returns:
<ruby>
def initializers
@initializers ||= self.class.initializers_for(self)
end
def initializers
@initializers ||= self.class.initializers_for(self)
end
</ruby>
If +@initializers+ isn't set (which it won't be at this point), the +intializers_for+ method will be called for this class.
<ruby>
def initializers_for(binding)
Collection.new(initializers_chain.map { |i| i.bind(binding) })
end
def initializers_for(binding)
Collection.new(initializers_chain.map { |i| i.bind(binding) })
end
</ruby>
The +Collection+ class in +railties/lib/rails/initializable.rb+ inherits from +Array+ and includes the +TSort+ module which is used to sort out the order of the initializers based on the order they are placed in.
@ -847,22 +848,22 @@ The +Collection+ class in +railties/lib/rails/initializable.rb+ inherits from +A
The +initializers_chain+ method referenced in the +initializers_for+ method is defined like this:
<rub>
def initializers_chain
initializers = Collection.new
ancestors.reverse_each do | klass |
next unless klass.respond_to?(:initializers)
initializers = initializers + klass.initializers
end
initializers
def initializers_chain
initializers = Collection.new
ancestors.reverse_each do | klass |
next unless klass.respond_to?(:initializers)
initializers = initializers + klass.initializers
end
initializers
end
</ruby>
This method collects the initializers from the ancestors of this class and adds them to a new +Collection+ object using the <tt>+</tt> method which is defined like this for the <tt>Collection</tt> class:
<ruby>
def +(other)
Collection.new(to_a + other.to_a)
end
def +(other)
Collection.new(to_a + other.to_a)
end
</ruby>
So this <tt>+</tt> method is overridden to return a new collection comprising of the existing collection as an array and then using the <tt>Array#+</tt> method combines these two collections, returning a "super" +Collection+ object. In this case, the only initializer that's going to be in this new +Collection+ object is the +i18n.callbacks+ initializer.
@ -870,34 +871,34 @@ So this <tt>+</tt> method is overridden to return a new collection comprising of
The next method to be called after this +initializer+ method is the +after_initialize+ method on the +config+ object, which is defined like this:
<ruby>
def after_initialize(&block)
ActiveSupport.on_load(:after_initialize, :yield => true, &block)
end
def after_initialize(&block)
ActiveSupport.on_load(:after_initialize, :yield => true, &block)
end
</ruby>
The +on_load+ method here is provided by the +active_support/lazy_load_hooks+ file which was required earlier and is defined like this:
<ruby>
def self.on_load(name, options = {}, &block)
if base = @loaded[name]
execute_hook(base, options, block)
else
@load_hooks[name] << [block, options]
end
def self.on_load(name, options = {}, &block)
if base = @loaded[name]
execute_hook(base, options, block)
else
@load_hooks[name] << [block, options]
end
end
</ruby>
The +@loaded+ variable here is a hash containing elements representing the different components of Rails that have been loaded at this stage. Currently, this hash is empty. So the +else+ is executed here, using the +@load_hooks+ variable defined in +active_support/lazy_load_hooks+:
<ruby>
@load_hooks = Hash.new {|h,k| h[k] = [] }
@load_hooks = Hash.new {|h,k| h[k] = [] }
</ruby>
This defines a new hash which has keys that default to empty arrays. This saves Rails from having to do something like this instead:
<ruby>
@load_hooks[name] = []
@load_hooks[name] << [block, options]
@load_hooks[name] = []
@load_hooks[name] << [block, options]
</ruby>
The value added to this array here consists of the block and options passed to +after_initialize+.
@ -929,11 +930,11 @@ h4. +activesupport/lib/action_dispatch.rb+
This file attempts to locate the +active_support+ and +active_model+ libraries by looking a couple of directories back from the current file and then adds the +active_support+ and +active_model+ +lib+ directories to the load path, but only if they aren't already, which they are.
<ruby>
activesupport_path = File.expand_path('../../../activesupport/lib', __FILE__)
$:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path)
activesupport_path = File.expand_path('../../../activesupport/lib', __FILE__)
$:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path)
activemodel_path = File.expand_path('../../../activemodel/lib', __FILE__)
$:.unshift(activemodel_path) if File.directory?(activemodel_path) && !$:.include?(activemodel_path)
activemodel_path = File.expand_path('../../../activemodel/lib', __FILE__)
$:.unshift(activemodel_path) if File.directory?(activemodel_path) && !$:.include?(activemodel_path)
</ruby>
In effect, these lines only define the +activesupport_path+ and +activemodel_path+ variables and nothing more.
@ -941,23 +942,23 @@ In effect, these lines only define the +activesupport_path+ and +activemodel_pat
The next two requires in this file are already done, so they are not run:
<ruby>
require 'active_support'
require 'active_support/dependencies/autoload'
require 'active_support'
require 'active_support/dependencies/autoload'
</ruby>
The following require is to +action_pack+ (+activesupport/lib/action_pack.rb+) which has a 22-line copyright notice at the top of it and ends in a simple require to +action_pack/version+. This file, like other +version.rb+ files before it, defines the +ActionPack::VERSION+ constant:
<ruby>
module ActionPack
module VERSION #:nodoc:
MAJOR = 3
MINOR = 1
TINY = 0
PRE = "beta"
module ActionPack
module VERSION #:nodoc:
MAJOR = 3
MINOR = 1
TINY = 0
PRE = "beta"
STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
end
STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
end
end
</ruby>
Once +action_pack+ is finished, then +active_model+ is required.
@ -967,16 +968,16 @@ h4. +activemodel/lib/active_model.rb+
This file makes a require to +active_model/version+ which defines the version for Active Model:
<ruby>
module ActiveModel
module VERSION #:nodoc:
MAJOR = 3
MINOR = 1
TINY = 0
PRE = "beta"
module ActiveModel
module VERSION #:nodoc:
MAJOR = 3
MINOR = 1
TINY = 0
PRE = "beta"
STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
end
STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
end
end
</ruby>
Once the +version.rb+ file is loaded, the +ActiveModel+ module has its autoloaded constants defined as well as a sub-module called +ActiveModel::Serializers+ which has autoloads of its own. When the +ActiveModel+ module is closed the +active_support/i18n+ file is required.
@ -986,15 +987,15 @@ h4. +activesupport/lib/active_support/i18n.rb+
This is where the +i18n+ gem is required and first configured:
<ruby>
begin
require 'i18n'
require 'active_support/lazy_load_hooks'
rescue LoadError => e
$stderr.puts "You don't have i18n installed in your application. Please add it to your Gemfile and run bundle install"
raise e
end
begin
require 'i18n'
require 'active_support/lazy_load_hooks'
rescue LoadError => e
$stderr.puts "You don't have i18n installed in your application. Please add it to your Gemfile and run bundle install"
raise e
end
I18n.load_path << "#{File.dirname(__FILE__)}/locale/en.yml"
I18n.load_path << "#{File.dirname(__FILE__)}/locale/en.yml"
</ruby>
In effect, the +I18n+ module first defined by +i18n_railtie+ is extended by the +i18n+ gem, rather than the other way around. This has no ill effect. They both work on the same way.
@ -1012,9 +1013,9 @@ h4. Back to +activesupport/lib/action_dispatch.rb+
The remainder of this file requires the +rack+ file from the Rack gem which defines the +Rack+ module. After +rack+, there's autoloads defined for the +Rack+, +ActionDispatch+, +ActionDispatch::Http+, +ActionDispatch::Session+. A new method called +autoload_under+ is used here, and this simply prefixes the files where the modules are autoloaded from with the path specified. For example here:
<ruby>
autoload_under 'testing' do
autoload :Assertions
...
autoload_under 'testing' do
autoload :Assertions
...
</ruby>
The +Assertions+ module is in the +action_dispatch/testing+ folder rather than simply +action_dispatch+.
@ -1046,25 +1047,25 @@ This file begins by detecting if the +lib+ directories of +active_support+ and +
The first three requires have already been done by other files and so aren't loaded here, but the 4th require, the one to +arel+ will require the file provided by the Arel gem, which defines the +Arel+ module.
<ruby>
require 'active_support'
require 'active_support/i18n'
require 'active_model'
require 'arel'
require 'active_support'
require 'active_support/i18n'
require 'active_model'
require 'arel'
</ruby>
The 5th require in this file is one to +active_record/version+ which defines the +ActiveRecord::VERSION+ constant:
<ruby>
module ActiveRecord
module VERSION #:nodoc:
MAJOR = 3
MINOR = 1
TINY = 0
PRE = "beta"
module ActiveRecord
module VERSION #:nodoc:
MAJOR = 3
MINOR = 1
TINY = 0
PRE = "beta"
STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
end
STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
end
end
</ruby>
Once these requires are finished, the base for the +ActiveRecord+ module is defined along with its autoloads.
@ -1072,9 +1073,9 @@ Once these requires are finished, the base for the +ActiveRecord+ module is defi
Near the end of the file, we see this line:
<ruby>
ActiveSupport.on_load(:active_record) do
Arel::Table.engine = self
end
ActiveSupport.on_load(:active_record) do
Arel::Table.engine = self
end
</ruby>
This will set the engine for +Arel::Table+ to be +ActiveRecord::Base+.
@ -1082,7 +1083,7 @@ This will set the engine for +Arel::Table+ to be +ActiveRecord::Base+.
The file then finishes with this line:
<ruby>
I18n.load_path << File.dirname(__FILE__) + '/active_record/locale/en.yml'
I18n.load_path << File.dirname(__FILE__) + '/active_record/locale/en.yml'
</ruby>
This will add the translations from +activerecord/lib/active_record/locale/en.yml+ to the load path for +I18n+, with this file being parsed when all the translations are loaded.
@ -1092,8 +1093,8 @@ h4. Back to +activerecord/lib/active_record/railtie.rb+
The next two <tt>require</tt>s in this file aren't run because their files are already required, with +rails+ being required by +rails/all+ and +active_model/railtie+ being required from +action_dispatch+.
<ruby>
require "rails"
require "active_model/railtie"
require "rails"
require "active_model/railtie"
</ruby>
The next +require+ in this file is to +action_controller/railtie+.
@ -1103,9 +1104,9 @@ h4. +actionpack/lib/action_controller/railtie.rb+
This file begins with a couple more requires to files that have already been loaded:
<ruby>
require "rails"
require "action_controller"
require "action_dispatch/railtie"
require "rails"
require "action_controller"
require "action_dispatch/railtie"
</ruby>
However the require after these is to a file that hasn't yet been loaded, +action_view/railtie+, which begins by requiring +action_view+.