aboutsummaryrefslogtreecommitdiffstats
path: root/railties/guides/source/initialization.textile
diff options
context:
space:
mode:
Diffstat (limited to 'railties/guides/source/initialization.textile')
-rw-r--r--railties/guides/source/initialization.textile627
1 files changed, 314 insertions, 313 deletions
diff --git a/railties/guides/source/initialization.textile b/railties/guides/source/initialization.textile
index 638830cd83..340699419b 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,17 +653,17 @@ 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.
+The +active_support/inflector/methods+ file has already been required by +active_support/autoload+ and so won't be loaded again here. The +activesupport/lib/active_support/inflector/inflections.rb+ is required by +active_support/inflector/methods+.
-h4. +activesupport/lib/active_support/inflector/inflections.rb+
+h4. +active_support/inflections+
This file references the +ActiveSupport::Inflector+ constant which isn't loaded by this point. But there were autoloads set up in +activesupport/lib/active_support.rb+ which will load the file which loads this constant and so then it will be defined. Then this file defines pluralization and singularization rules for words in Rails. This is how Rails knows how to pluralize "tomato" to "tomatoes".
@@ -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+.