aboutsummaryrefslogtreecommitdiffstats
path: root/railties/guides/source/initialization.textile
diff options
context:
space:
mode:
authorXavier Noria <fxn@hashref.com>2011-06-06 22:23:30 +0200
committerXavier Noria <fxn@hashref.com>2011-06-06 22:23:30 +0200
commit5e21247131fa7d5484190c9a71b74f9d3f090684 (patch)
tree5eee39fcabb952cafd513caf7e67943bc6b26e98 /railties/guides/source/initialization.textile
parent38ad6bb2f566202dd522a0cf31a55a746f122d53 (diff)
parent689e12b828665b7b2cfcda85d46249c5cf2aa713 (diff)
downloadrails-5e21247131fa7d5484190c9a71b74f9d3f090684.tar.gz
rails-5e21247131fa7d5484190c9a71b74f9d3f090684.tar.bz2
rails-5e21247131fa7d5484190c9a71b74f9d3f090684.zip
Merge branch 'master' of git://github.com/lifo/docrails
Conflicts: activerecord/RUNNING_UNIT_TESTS
Diffstat (limited to 'railties/guides/source/initialization.textile')
-rw-r--r--railties/guides/source/initialization.textile623
1 files changed, 312 insertions, 311 deletions
diff --git a/railties/guides/source/initialization.textile b/railties/guides/source/initialization.textile
index 638830cd83..1d5b0c0c11 100644
--- a/railties/guides/source/initialization.textile
+++ b/railties/guides/source/initialization.textile
@@ -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
-
- begin
- require "rails/cli"
- rescue LoadError
- railties_path = File.expand_path('../../railties/lib', __FILE__)
- $:.unshift(railties_path)
- require "rails/cli"
- end
+#!/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
</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"))
-
- 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
- }
+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
+ }
</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]
-
- #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]
+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]
+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,57 +848,57 @@ 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 overriden 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.
+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.
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"
-
- STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
- end
+module ActionPack
+ module VERSION #:nodoc:
+ MAJOR = 3
+ MINOR = 1
+ TINY = 0
+ PRE = "beta"
+
+ 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"
-
- STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
- end
+module ActiveModel
+ module VERSION #:nodoc:
+ MAJOR = 3
+ MINOR = 1
+ TINY = 0
+ PRE = "beta"
+
+ 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"
-
- STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
- end
+module ActiveRecord
+ module VERSION #:nodoc:
+ MAJOR = 3
+ MINOR = 1
+ TINY = 0
+ PRE = "beta"
+
+ 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+.