aboutsummaryrefslogtreecommitdiffstats
path: root/railties/lib/rails/initializer.rb
diff options
context:
space:
mode:
authorYehuda Katz + Carl Lerche <ykatz+clerche@engineyard.com>2009-09-24 14:01:31 -0700
committerYehuda Katz + Carl Lerche <ykatz+clerche@engineyard.com>2009-09-24 16:11:41 -0700
commitf0dd77c6be6a86fe384bb0015151e0a497973d39 (patch)
treead81bb4c807c39edeaa37035882a16d9d95ebaa9 /railties/lib/rails/initializer.rb
parent610b81beca461a6fa4f00c7023e0e4315eb2b8be (diff)
downloadrails-f0dd77c6be6a86fe384bb0015151e0a497973d39.tar.gz
rails-f0dd77c6be6a86fe384bb0015151e0a497973d39.tar.bz2
rails-f0dd77c6be6a86fe384bb0015151e0a497973d39.zip
Move railties/lib/* into railties/lib/*
Diffstat (limited to 'railties/lib/rails/initializer.rb')
-rw-r--r--railties/lib/rails/initializer.rb578
1 files changed, 578 insertions, 0 deletions
diff --git a/railties/lib/rails/initializer.rb b/railties/lib/rails/initializer.rb
new file mode 100644
index 0000000000..b91e07d5c4
--- /dev/null
+++ b/railties/lib/rails/initializer.rb
@@ -0,0 +1,578 @@
+require "pathname"
+
+require 'rails/railties_path'
+require 'rails/version'
+require 'rails/gem_dependency'
+require 'rails/rack'
+require 'rails/paths'
+require 'rails/core'
+require 'rails/configuration'
+
+RAILS_ENV = (ENV['RAILS_ENV'] || 'development').dup unless defined?(RAILS_ENV)
+
+module Rails
+ # Sanity check to make sure this file is only loaded once
+ # TODO: Get to the point where this can be removed.
+ raise "It looks like initializer.rb was required twice" if defined?(Initializer)
+
+ class Initializer
+ class Error < StandardError ; end
+
+ class Base
+ class << self
+ def run(&blk)
+ define_method(:run, &blk)
+ end
+
+ def config=(config)
+ @@config = config
+ end
+
+ def config
+ @@config
+ end
+ alias configuration config
+
+ def gems_dependencies_loaded
+ config.gems_dependencies_loaded
+ end
+
+ def plugin_loader
+ @plugin_loader ||= configuration.plugin_loader.new(self)
+ end
+ end
+
+ def gems_dependencies_loaded
+ self.class.gems_dependencies_loaded
+ end
+
+ def plugin_loader
+ self.class.plugin_loader
+ end
+ end
+
+ class Runner
+
+ attr_reader :names, :initializers
+ attr_accessor :config
+ alias configuration config
+
+ def initialize(parent = nil)
+ @names = parent ? parent.names.dup : {}
+ @initializers = parent ? parent.initializers.dup : []
+ end
+
+ def add(name, options = {}, &block)
+ # If :before or :after is specified, set the index to the right spot
+ if other = options[:before] || options[:after]
+ raise Error, "The #{other.inspect} initializer does not exist" unless @names[other]
+ index = @initializers.index(@names[other])
+ index += 1 if options[:after]
+ end
+
+ @initializers.insert(index || -1, block)
+ @names[name] = block
+ end
+
+ def delete(name)
+ @names[name].tap do |initializer|
+ @initializers.delete(initializer)
+ @names.delete(name)
+ end
+ end
+
+ def run_initializer(initializer)
+ init_block = initializer.is_a?(Proc) ? initializer : @names[initializer]
+ container = Class.new(Base, &init_block).new
+ container.run if container.respond_to?(:run)
+ end
+
+ def run(initializer = nil)
+ Rails.configuration = Base.config = @config
+
+ if initializer
+ run_initializer(initializer)
+ else
+ @initializers.each {|block| run_initializer(block) }
+ end
+ end
+ end
+
+ def self.default
+ @default ||= Runner.new
+ end
+
+ def self.run(initializer = nil, config = nil)
+ default.config = config if config
+ default.config ||= Configuration.new
+ yield default.config if block_given?
+ default.run(initializer)
+ end
+ end
+
+ # Check for valid Ruby version (1.8.2 or 1.8.4 or higher). This is done in an
+ # external file, so we can use it from the `rails` program as well without duplication.
+ Initializer.default.add :check_ruby_version do
+ require 'rails/ruby_version_check'
+ end
+
+ # If Rails is vendored and RubyGems is available, install stub GemSpecs
+ # for Rails, Active Support, Active Record, Action Pack, Action Mailer, and
+ # Active Resource. This allows Gem plugins to depend on Rails even when
+ # the Gem version of Rails shouldn't be loaded.
+ Initializer.default.add :install_gem_spec_stubs do
+ unless Rails.respond_to?(:vendor_rails?)
+ abort %{Your config/boot.rb is outdated: Run "rake rails:update".}
+ end
+
+ if Rails.vendor_rails?
+ begin; require "rubygems"; rescue LoadError; return; end
+
+ %w(rails activesupport activerecord actionpack actionmailer activeresource).each do |stub|
+ Gem.loaded_specs[stub] ||= Gem::Specification.new do |s|
+ s.name = stub
+ s.version = Rails::VERSION::STRING
+ s.loaded_from = ""
+ end
+ end
+ end
+ end
+
+ # Set the <tt>$LOAD_PATH</tt> based on the value of
+ # Configuration#load_paths. Duplicates are removed.
+ Initializer.default.add :set_load_path do
+ # TODO: Think about unifying this with the general Rails paths
+ configuration.framework_paths.reverse_each { |dir| $LOAD_PATH.unshift(dir) if File.directory?(dir) }
+ configuration.paths.add_to_load_path
+ $LOAD_PATH.uniq!
+ end
+
+ # Requires all frameworks specified by the Configuration#frameworks
+ # list. By default, all frameworks (Active Record, Active Support,
+ # Action Pack, Action Mailer, and Active Resource) are loaded.
+ Initializer.default.add :require_frameworks do
+ begin
+ require 'active_support'
+ require 'active_support/core_ext/kernel/reporting'
+ require 'active_support/core_ext/logger'
+
+ # TODO: This is here to make Sam Ruby's tests pass. Needs discussion.
+ require 'active_support/core_ext/numeric/bytes'
+ configuration.frameworks.each { |framework| require(framework.to_s) }
+ rescue LoadError => e
+ # Re-raise as RuntimeError because Mongrel would swallow LoadError.
+ raise e.to_s
+ end
+ end
+
+ # Set the paths from which Rails will automatically load source files, and
+ # the load_once paths.
+ Initializer.default.add :set_autoload_paths do
+ require 'active_support/dependencies'
+ ActiveSupport::Dependencies.load_paths = configuration.load_paths.uniq
+ ActiveSupport::Dependencies.load_once_paths = configuration.load_once_paths.uniq
+
+ extra = ActiveSupport::Dependencies.load_once_paths - ActiveSupport::Dependencies.load_paths
+ unless extra.empty?
+ abort <<-end_error
+ load_once_paths must be a subset of the load_paths.
+ Extra items in load_once_paths: #{extra * ','}
+ end_error
+ end
+
+ # Freeze the arrays so future modifications will fail rather than do nothing mysteriously
+ configuration.load_once_paths.freeze
+ end
+
+ # Adds all load paths from plugins to the global set of load paths, so that
+ # code from plugins can be required (explicitly or automatically via ActiveSupport::Dependencies).
+ Initializer.default.add :add_plugin_load_paths do
+ require 'active_support/dependencies'
+ plugin_loader.add_plugin_load_paths
+ end
+
+ # Loads the environment specified by Configuration#environment_path, which
+ # is typically one of development, test, or production.
+ Initializer.default.add :load_environment do
+ silence_warnings do
+ next if @environment_loaded
+ next unless File.file?(configuration.environment_path)
+
+ @environment_loaded = true
+
+ config = configuration
+ constants = self.class.constants
+
+ eval(IO.read(configuration.environment_path), binding, configuration.environment_path)
+
+ (self.class.constants - constants).each do |const|
+ Object.const_set(const, self.class.const_get(const))
+ end
+ end
+ end
+
+ Initializer.default.add :add_gem_load_paths do
+ require 'rails/gem_dependency'
+ Rails::GemDependency.add_frozen_gem_path
+ unless config.gems.empty?
+ require "rubygems"
+ config.gems.each { |gem| gem.add_load_paths }
+ end
+ end
+
+ # Preload all frameworks specified by the Configuration#frameworks.
+ # Used by Passenger to ensure everything's loaded before forking and
+ # to avoid autoload race conditions in JRuby.
+ Initializer.default.add :preload_frameworks do
+ if configuration.preload_frameworks
+ configuration.frameworks.each do |framework|
+ # String#classify and #constantize aren't available yet.
+ toplevel = Object.const_get(framework.to_s.gsub(/(?:^|_)(.)/) { $1.upcase })
+ toplevel.load_all! if toplevel.respond_to?(:load_all!)
+ end
+ end
+ end
+
+ # For Ruby 1.8, this initialization sets $KCODE to 'u' to enable the
+ # multibyte safe operations. Plugin authors supporting other encodings
+ # should override this behaviour and set the relevant +default_charset+
+ # on ActionController::Base.
+ #
+ # For Ruby 1.9, UTF-8 is the default internal and external encoding.
+ Initializer.default.add :initialize_encoding do
+ if RUBY_VERSION < '1.9'
+ $KCODE='u'
+ else
+ Encoding.default_external = Encoding::UTF_8
+ end
+ end
+
+ # This initialization routine does nothing unless <tt>:active_record</tt>
+ # is one of the frameworks to load (Configuration#frameworks). If it is,
+ # this sets the database configuration from Configuration#database_configuration
+ # and then establishes the connection.
+ Initializer.default.add :initialize_database do
+ if configuration.frameworks.include?(:active_record)
+ ActiveRecord::Base.configurations = configuration.database_configuration
+ ActiveRecord::Base.establish_connection
+ end
+ end
+
+ Initializer.default.add :initialize_cache do
+ unless defined?(RAILS_CACHE)
+ silence_warnings { Object.const_set "RAILS_CACHE", ActiveSupport::Cache.lookup_store(configuration.cache_store) }
+
+ if RAILS_CACHE.respond_to?(:middleware)
+ # Insert middleware to setup and teardown local cache for each request
+ configuration.middleware.insert_after(:"Rack::Lock", RAILS_CACHE.middleware)
+ end
+ end
+ end
+
+ Initializer.default.add :initialize_framework_caches do
+ if configuration.frameworks.include?(:action_controller)
+ ActionController::Base.cache_store ||= RAILS_CACHE
+ end
+ end
+
+ Initializer.default.add :initialize_logger do
+ # if the environment has explicitly defined a logger, use it
+ next if Rails.logger
+
+ unless logger = configuration.logger
+ begin
+ logger = ActiveSupport::BufferedLogger.new(configuration.log_path)
+ logger.level = ActiveSupport::BufferedLogger.const_get(configuration.log_level.to_s.upcase)
+ if RAILS_ENV == "production"
+ logger.auto_flushing = false
+ end
+ rescue StandardError => e
+ logger = ActiveSupport::BufferedLogger.new(STDERR)
+ logger.level = ActiveSupport::BufferedLogger::WARN
+ logger.warn(
+ "Rails Error: Unable to access log file. Please ensure that #{configuration.log_path} exists and is chmod 0666. " +
+ "The log level has been raised to WARN and the output directed to STDERR until the problem is fixed."
+ )
+ end
+ end
+
+ # TODO: Why are we silencing warning here?
+ silence_warnings { Object.const_set "RAILS_DEFAULT_LOGGER", logger }
+ end
+
+ # Sets the logger for Active Record, Action Controller, and Action Mailer
+ # (but only for those frameworks that are to be loaded). If the framework's
+ # logger is already set, it is not changed, otherwise it is set to use
+ # RAILS_DEFAULT_LOGGER.
+ Initializer.default.add :initialize_framework_logging do
+ for framework in ([ :active_record, :action_controller, :action_mailer ] & configuration.frameworks)
+ framework.to_s.camelize.constantize.const_get("Base").logger ||= Rails.logger
+ end
+
+ ActiveSupport::Dependencies.logger ||= Rails.logger
+ Rails.cache.logger ||= Rails.logger
+ end
+
+ # Sets the dependency loading mechanism based on the value of
+ # Configuration#cache_classes.
+ Initializer.default.add :initialize_dependency_mechanism do
+ # TODO: Remove files from the $" and always use require
+ ActiveSupport::Dependencies.mechanism = configuration.cache_classes ? :require : :load
+ end
+
+ # Loads support for "whiny nil" (noisy warnings when methods are invoked
+ # on +nil+ values) if Configuration#whiny_nils is true.
+ Initializer.default.add :initialize_whiny_nils do
+ require('active_support/whiny_nil') if configuration.whiny_nils
+ end
+
+
+ # Sets the default value for Time.zone, and turns on ActiveRecord::Base#time_zone_aware_attributes.
+ # If assigned value cannot be matched to a TimeZone, an exception will be raised.
+ Initializer.default.add :initialize_time_zone do
+ if configuration.time_zone
+ zone_default = Time.__send__(:get_zone, configuration.time_zone)
+
+ unless zone_default
+ raise \
+ 'Value assigned to config.time_zone not recognized.' +
+ 'Run "rake -D time" for a list of tasks for finding appropriate time zone names.'
+ end
+
+ Time.zone_default = zone_default
+
+ if configuration.frameworks.include?(:active_record)
+ ActiveRecord::Base.time_zone_aware_attributes = true
+ ActiveRecord::Base.default_timezone = :utc
+ end
+ end
+ end
+
+ # Set the i18n configuration from config.i18n but special-case for the load_path which should be
+ # appended to what's already set instead of overwritten.
+ Initializer.default.add :initialize_i18n do
+ configuration.i18n.each do |setting, value|
+ if setting == :load_path
+ I18n.load_path += value
+ else
+ I18n.send("#{setting}=", value)
+ end
+ end
+ end
+
+ # Initializes framework-specific settings for each of the loaded frameworks
+ # (Configuration#frameworks). The available settings map to the accessors
+ # on each of the corresponding Base classes.
+ Initializer.default.add :initialize_framework_settings do
+ configuration.frameworks.each do |framework|
+ base_class = framework.to_s.camelize.constantize.const_get("Base")
+
+ configuration.send(framework).each do |setting, value|
+ base_class.send("#{setting}=", value)
+ end
+ end
+ configuration.active_support.each do |setting, value|
+ ActiveSupport.send("#{setting}=", value)
+ end
+ end
+
+ # Sets +ActionController::Base#view_paths+ and +ActionMailer::Base#template_root+
+ # (but only for those frameworks that are to be loaded). If the framework's
+ # paths have already been set, it is not changed, otherwise it is
+ # set to use Configuration#view_path.
+ Initializer.default.add :initialize_framework_views do
+ if configuration.frameworks.include?(:action_view)
+ view_path = ActionView::PathSet.type_cast(configuration.view_path)
+ ActionMailer::Base.template_root = view_path if configuration.frameworks.include?(:action_mailer) && ActionMailer::Base.view_paths.blank?
+ ActionController::Base.view_paths = view_path if configuration.frameworks.include?(:action_controller) && ActionController::Base.view_paths.blank?
+ end
+ end
+
+ Initializer.default.add :initialize_metal do
+ # TODO: Make Rails and metal work without ActionController
+ if defined?(ActionController)
+ Rails::Rack::Metal.requested_metals = configuration.metals
+ Rails::Rack::Metal.metal_paths += plugin_loader.engine_metal_paths
+
+ configuration.middleware.insert_before(
+ :"ActionDispatch::ParamsParser",
+ Rails::Rack::Metal, :if => Rails::Rack::Metal.metals.any?)
+ end
+ end
+
+ Initializer.default.add :check_for_unbuilt_gems do
+ unbuilt_gems = config.gems.select {|gem| gem.frozen? && !gem.built? }
+ if unbuilt_gems.size > 0
+ # don't print if the gems:build rake tasks are being run
+ unless $gems_build_rake_task
+ abort <<-end_error
+The following gems have native components that need to be built
+#{unbuilt_gems.map { |gemm| "#{gemm.name} #{gemm.requirement}" } * "\n "}
+
+You're running:
+ruby #{Gem.ruby_version} at #{Gem.ruby}
+rubygems #{Gem::RubyGemsVersion} at #{Gem.path * ', '}
+
+Run `rake gems:build` to build the unbuilt gems.
+ end_error
+ end
+ end
+ end
+
+ Initializer.default.add :load_gems do
+ unless $gems_rake_task
+ config.gems.each { |gem| gem.load }
+ end
+ end
+
+ # Loads all plugins in <tt>config.plugin_paths</tt>. <tt>plugin_paths</tt>
+ # defaults to <tt>vendor/plugins</tt> but may also be set to a list of
+ # paths, such as
+ # config.plugin_paths = ["#{RAILS_ROOT}/lib/plugins", "#{RAILS_ROOT}/vendor/plugins"]
+ #
+ # In the default implementation, as each plugin discovered in <tt>plugin_paths</tt> is initialized:
+ # * its +lib+ directory, if present, is added to the load path (immediately after the applications lib directory)
+ # * <tt>init.rb</tt> is evaluated, if present
+ #
+ # After all plugins are loaded, duplicates are removed from the load path.
+ # If an array of plugin names is specified in config.plugins, only those plugins will be loaded
+ # and they plugins will be loaded in that order. Otherwise, plugins are loaded in alphabetical
+ # order.
+ #
+ # if config.plugins ends contains :all then the named plugins will be loaded in the given order and all other
+ # plugins will be loaded in alphabetical order
+ Initializer.default.add :load_plugins do
+ plugin_loader.load_plugins
+ end
+
+ #
+ # # pick up any gems that plugins depend on
+ Initializer.default.add :add_gem_load_paths do
+ require 'rails/gem_dependency'
+ # TODO: This seems extraneous
+ Rails::GemDependency.add_frozen_gem_path
+ unless config.gems.empty?
+ require "rubygems"
+ config.gems.each { |gem| gem.add_load_paths }
+ end
+ end
+
+ # TODO: Figure out if this needs to run a second time
+ # load_gems
+
+ Initializer.default.add :check_gem_dependencies do
+ unloaded_gems = config.gems.reject { |g| g.loaded? }
+ if unloaded_gems.size > 0
+ configuration.gems_dependencies_loaded = false
+ # don't print if the gems rake tasks are being run
+ unless $gems_rake_task
+ abort <<-end_error
+Missing these required gems:
+#{unloaded_gems.map { |gemm| "#{gemm.name} #{gemm.requirement}" } * "\n "}
+
+You're running:
+ruby #{Gem.ruby_version} at #{Gem.ruby}
+rubygems #{Gem::RubyGemsVersion} at #{Gem.path * ', '}
+
+Run `rake gems:install` to install the missing gems.
+ end_error
+ end
+ else
+ configuration.gems_dependencies_loaded = true
+ end
+ end
+
+ # # bail out if gems are missing - note that check_gem_dependencies will have
+ # # already called abort() unless $gems_rake_task is set
+ # return unless gems_dependencies_loaded
+
+ Initializer.default.add :load_application_initializers do
+ if gems_dependencies_loaded
+ Dir["#{configuration.root_path}/config/initializers/**/*.rb"].sort.each do |initializer|
+ load(initializer)
+ end
+ end
+ end
+
+ # Fires the user-supplied after_initialize block (Configuration#after_initialize)
+ Initializer.default.add :after_initialize do
+ if gems_dependencies_loaded
+ configuration.after_initialize_blocks.each do |block|
+ block.call
+ end
+ end
+ end
+
+ # # Setup database middleware after initializers have run
+ Initializer.default.add :initialize_database_middleware do
+ if configuration.frameworks.include?(:active_record)
+ if configuration.frameworks.include?(:action_controller) &&
+ ActionController::Base.session_store.name == 'ActiveRecord::SessionStore'
+ configuration.middleware.insert_before :"ActiveRecord::SessionStore", ActiveRecord::ConnectionAdapters::ConnectionManagement
+ configuration.middleware.insert_before :"ActiveRecord::SessionStore", ActiveRecord::QueryCache
+ else
+ configuration.middleware.use ActiveRecord::ConnectionAdapters::ConnectionManagement
+ configuration.middleware.use ActiveRecord::QueryCache
+ end
+ end
+ end
+
+ # TODO: Make a DSL way to limit an initializer to a particular framework
+
+ # # Prepare dispatcher callbacks and run 'prepare' callbacks
+ Initializer.default.add :prepare_dispatcher do
+ next unless configuration.frameworks.include?(:action_controller)
+ require 'rails/dispatcher' unless defined?(::Dispatcher)
+ Dispatcher.define_dispatcher_callbacks(configuration.cache_classes)
+ end
+
+ # Routing must be initialized after plugins to allow the former to extend the routes
+ # ---
+ # If Action Controller is not one of the loaded frameworks (Configuration#frameworks)
+ # this does nothing. Otherwise, it loads the routing definitions and sets up
+ # loading module used to lazily load controllers (Configuration#controller_paths).
+ Initializer.default.add :initialize_routing do
+ next unless configuration.frameworks.include?(:action_controller)
+
+ ActionController::Routing.controller_paths += configuration.controller_paths
+ ActionController::Routing::Routes.add_configuration_file(configuration.routes_configuration_file)
+ ActionController::Routing::Routes.reload!
+ end
+ #
+ # # Observers are loaded after plugins in case Observers or observed models are modified by plugins.
+ Initializer.default.add :load_observers do
+ if gems_dependencies_loaded && configuration.frameworks.include?(:active_record)
+ ActiveRecord::Base.instantiate_observers
+ end
+ end
+
+ # Eager load application classes
+ Initializer.default.add :load_application_classes do
+ next if $rails_rake_task
+
+ if configuration.cache_classes
+ configuration.eager_load_paths.each do |load_path|
+ matcher = /\A#{Regexp.escape(load_path)}(.*)\.rb\Z/
+ Dir.glob("#{load_path}/**/*.rb").sort.each do |file|
+ require_dependency file.sub(matcher, '\1')
+ end
+ end
+ end
+ end
+
+ # Disable dependency loading during request cycle
+ Initializer.default.add :disable_dependency_loading do
+ if configuration.cache_classes && !configuration.dependency_loading
+ ActiveSupport::Dependencies.unhook!
+ end
+ end
+
+ # Configure generators if they were already loaded
+ Initializer.default.add :initialize_generators do
+ if defined?(Rails::Generators)
+ Rails::Generators.no_color! unless config.generators.colorize_logging
+ Rails::Generators.aliases.deep_merge! config.generators.aliases
+ Rails::Generators.options.deep_merge! config.generators.options
+ end
+ end
+end