initializer.rb 33.5 KB
Newer Older
1
require 'logger'
2
require 'set'
3 4 5 6 7 8 9
require 'pathname'

$LOAD_PATH.unshift File.dirname(__FILE__)
require 'railties_path'
require 'rails/version'
require 'rails/plugin/locator'
require 'rails/plugin/loader'
10
require 'rails/gem_dependency'
11
require 'rails/rack'
12

13

14
RAILS_ENV = (ENV['RAILS_ENV'] || 'development').dup unless defined?(RAILS_ENV)
15 16

module Rails
D
David Heinemeier Hansson 已提交
17 18 19 20 21
  class << self
    # The Configuration instance used to configure the Rails environment
    def configuration
      @@configuration
    end
J
Joshua Peek 已提交
22

D
David Heinemeier Hansson 已提交
23 24 25
    def configuration=(configuration)
      @@configuration = configuration
    end
J
Joshua Peek 已提交
26 27 28 29 30 31 32 33 34

    def initialized?
      @initialized || false
    end

    def initialized=(initialized)
      @initialized ||= initialized
    end

D
David Heinemeier Hansson 已提交
35 36 37
    def logger
      RAILS_DEFAULT_LOGGER
    end
J
Joshua Peek 已提交
38

D
David Heinemeier Hansson 已提交
39
    def root
40 41 42 43 44
      if defined?(RAILS_ROOT)
        RAILS_ROOT
      else
        nil
      end
D
David Heinemeier Hansson 已提交
45
    end
J
Joshua Peek 已提交
46

D
David Heinemeier Hansson 已提交
47
    def env
48
      ActiveSupport::StringInquirer.new(RAILS_ENV)
D
David Heinemeier Hansson 已提交
49
    end
J
Joshua Peek 已提交
50

D
David Heinemeier Hansson 已提交
51 52 53
    def cache
      RAILS_CACHE
    end
54

55 56 57 58
    def version
      VERSION::STRING
    end

59
    def public_path
60
      @@public_path ||= self.root ? File.join(self.root, "public") : "public"
61 62 63 64 65
    end

    def public_path=(path)
      @@public_path = path
    end
66
  end
J
Joshua Peek 已提交
67

68 69 70 71
  # The Initializer is responsible for processing the Rails configuration, such
  # as setting the $LOAD_PATH, requiring the right frameworks, initializing
  # logging, and more. It can be run either as a single command that'll just
  # use the default configuration, like this:
72 73 74
  #
  #   Rails::Initializer.run
  #
75 76
  # But normally it's more interesting to pass in a custom configuration
  # through the block running:
77 78
  #
  #   Rails::Initializer.run do |config|
79
  #     config.frameworks -= [ :action_mailer ]
80 81
  #   end
  #
82 83
  # This will use the default configuration options from Rails::Configuration,
  # but allow for overwriting on select areas.
84
  class Initializer
85
    # The Configuration instance used by this Initializer instance.
86
    attr_reader :configuration
87 88 89

    # The set of loaded plugins.
    attr_reader :loaded_plugins
90 91 92 93

    # Whether or not all the gem dependencies have been met
    attr_reader :gems_dependencies_loaded

94 95 96 97 98 99 100
    # Runs the initializer. By default, this will invoke the #process method,
    # which simply executes all of the initialization routines. Alternately,
    # you can specify explicitly which initialization routine you want:
    #
    #   Rails::Initializer.run(:set_load_path)
    #
    # This is useful if you only want the load path initialized, without
P
Pratik Naik 已提交
101
    # incurring the overhead of completely loading the entire environment.
102 103
    def self.run(command = :process, configuration = Configuration.new)
      yield configuration if block_given?
104 105 106
      initializer = new configuration
      initializer.send(command)
      initializer
107
    end
108

109 110
    # Create a new Initializer instance that references the given Configuration
    # instance.
111 112
    def initialize(configuration)
      @configuration = configuration
113
      @loaded_plugins = []
114
    end
115

116
    # Sequentially step through all of the available initialization routines,
117
    # in order (view execution order in source).
118
    def process
119 120
      Rails.configuration = configuration

121
      check_ruby_version
122
      install_gem_spec_stubs
123
      set_load_path
124 125
      add_gem_load_paths

126
      require_frameworks
127
      set_autoload_paths
128
      add_plugin_load_paths
129
      load_environment
130

131
      initialize_encoding
132
      initialize_database
133 134 135 136

      initialize_cache
      initialize_framework_caches

137 138
      initialize_logger
      initialize_framework_logging
139

140 141
      initialize_dependency_mechanism
      initialize_whiny_nils
142
      initialize_temporary_session_directory
143
      initialize_time_zone
144
      initialize_framework_settings
145
      initialize_framework_views
146

147
      add_support_load_paths
J
Jamis Buck 已提交
148

149
      load_gems
J
Jamis Buck 已提交
150
      load_plugins
151 152 153 154

      # pick up any gems that plugins depend on
      add_gem_load_paths
      load_gems
155
      check_gem_dependencies
J
Joshua Peek 已提交
156

157 158
      load_application_initializers

159 160
      # the framework is now fully initialized
      after_initialize
161

162 163 164
      # Prepare dispatcher callbacks and run 'prepare' callbacks
      prepare_dispatcher

165 166 167 168 169
      # Routing must be initialized after plugins to allow the former to extend the routes
      initialize_routing

      # Observers are loaded after plugins in case Observers or observed models are modified by plugins.
      load_observers
J
Joshua Peek 已提交
170

171 172 173
      # Load view path cache
      load_view_paths

174
      # Load application classes
175 176
      load_application_classes

177 178 179
      # Disable dependency loading during request cycle
      disable_dependency_loading

J
Joshua Peek 已提交
180 181
      # Flag initialized
      Rails.initialized = true
182
    end
183 184 185 186

    # Check for valid Ruby version
    # This is done in an external file, so we can use it
    # from the `rails` program as well without duplication.
187
    def check_ruby_version
188 189 190
      require 'ruby_version_check'
    end

191
    # If Rails is vendored and RubyGems is available, install stub GemSpecs
P
Pratik Naik 已提交
192 193
    # for Rails, Active Support, Active Record, Action Pack, Action Mailer, and
    # Active Resource. This allows Gem plugins to depend on Rails even when
194 195
    # the Gem version of Rails shouldn't be loaded.
    def install_gem_spec_stubs
196
      unless Rails.respond_to?(:vendor_rails?)
P
Pratik Naik 已提交
197
        abort %{Your config/boot.rb is outdated: Run "rake rails:update".}
198 199
      end

200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
      if Rails.vendor_rails?
        begin; require "rubygems"; rescue LoadError; return; end

        stubs = %w(rails activesupport activerecord actionpack actionmailer activeresource)
        stubs.reject! { |s| Gem.loaded_specs.key?(s) }

        stubs.each do |stub|
          Gem.loaded_specs[stub] = Gem::Specification.new do |s|
            s.name = stub
            s.version = Rails::VERSION::STRING
          end
        end
      end
    end

215 216
    # Set the <tt>$LOAD_PATH</tt> based on the value of
    # Configuration#load_paths. Duplicates are removed.
217
    def set_load_path
218 219
      load_paths = configuration.load_paths + configuration.framework_paths
      load_paths.reverse_each { |dir| $LOAD_PATH.unshift(dir) if File.directory?(dir) }
220 221
      $LOAD_PATH.uniq!
    end
222

223 224
    # Set the paths from which Rails will automatically load source files, and
    # the load_once paths.
225
    def set_autoload_paths
226 227
      ActiveSupport::Dependencies.load_paths = configuration.load_paths.uniq
      ActiveSupport::Dependencies.load_once_paths = configuration.load_once_paths.uniq
228

229
      extra = ActiveSupport::Dependencies.load_once_paths - ActiveSupport::Dependencies.load_paths
230 231
      unless extra.empty?
        abort <<-end_error
232
          load_once_paths must be a subset of the load_paths.
233 234 235
          Extra items in load_once_paths: #{extra * ','}
        end_error
      end
236

237 238
      # Freeze the arrays so future modifications will fail rather than do nothing mysteriously
      configuration.load_once_paths.freeze
239
    end
240

241
    # Requires all frameworks specified by the Configuration#frameworks
P
Pratik Naik 已提交
242 243
    # list. By default, all frameworks (Active Record, Active Support,
    # Action Pack, Action Mailer, and Active Resource) are loaded.
244 245
    def require_frameworks
      configuration.frameworks.each { |framework| require(framework.to_s) }
246 247 248
    rescue LoadError => e
      # re-raise because Mongrel would swallow it
      raise e.to_s
249
    end
250

251 252
    # Add the load paths used by support functions such as the info controller
    def add_support_load_paths
253
    end
254

255
    # Adds all load paths from plugins to the global set of load paths, so that
256
    # code from plugins can be required (explicitly or automatically via ActiveSupport::Dependencies).
257 258 259 260
    def add_plugin_load_paths
      plugin_loader.add_plugin_load_paths
    end

261 262 263
    def add_gem_load_paths
      unless @configuration.gems.empty?
        require "rubygems"
264
        @configuration.gems.each { |gem| gem.add_load_paths }
265 266 267 268
      end
    end

    def load_gems
269
      @configuration.gems.each { |gem| gem.load }
270 271 272 273 274 275 276 277
    end

    def check_gem_dependencies
      unloaded_gems = @configuration.gems.reject { |g| g.loaded? }
      if unloaded_gems.size > 0
        @gems_dependencies_loaded = false
        # don't print if the gems rake tasks are being run
        unless $rails_gem_installer
278 279 280 281 282 283 284 285 286 287
          abort <<-end_error
Missing these required gems:
  #{unloaded_gems.map { |gem| "#{gem.name}  #{gem.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
288 289 290 291
        end
      else
        @gems_dependencies_loaded = true
      end
292 293
    end

294 295 296
    # 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
D
David Heinemeier Hansson 已提交
297
    #   config.plugin_paths = ["#{RAILS_ROOT}/lib/plugins", "#{RAILS_ROOT}/vendor/plugins"]
298
    #
299 300
    # 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)
301
    # * <tt>init.rb</tt> is evaluated, if present
302 303
    #
    # After all plugins are loaded, duplicates are removed from the load path.
304 305
    # 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
306
    # order.
307 308 309
    #
    # 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
J
Jamis Buck 已提交
310
    def load_plugins
311 312 313 314 315
      plugin_loader.load_plugins
    end

    def plugin_loader
      @plugin_loader ||= configuration.plugin_loader.new(self)
J
Jamis Buck 已提交
316 317
    end

318
    # Loads the environment specified by Configuration#environment_path, which
319
    # is typically one of development, test, or production.
320 321
    def load_environment
      silence_warnings do
322 323
        return if @environment_loaded
        @environment_loaded = true
J
Joshua Peek 已提交
324

325
        config = configuration
326
        constants = self.class.constants
J
Joshua Peek 已提交
327

328
        eval(IO.read(configuration.environment_path), binding, configuration.environment_path)
J
Joshua Peek 已提交
329

330 331 332
        (self.class.constants - constants).each do |const|
          Object.const_set(const, self.class.const_get(const))
        end
333
      end
334
    end
335 336

    def load_observers
337
      if gems_dependencies_loaded && configuration.frameworks.include?(:active_record)
338
        ActiveRecord::Base.instantiate_observers
339
      end
340 341
    end

342 343
    def load_view_paths
      ActionView::PathSet::Path.eager_load_templates! if configuration.cache_classes
344 345
      ActionMailer::Base.template_root.load if configuration.frameworks.include?(:action_mailer)
      ActionController::Base.view_paths.load if configuration.frameworks.include?(:action_controller)
346 347
    end

348
    # Eager load application classes
349
    def load_application_classes
350 351 352 353 354 355
      if configuration.cache_classes
        configuration.eager_load_paths.each do |load_path|
          Dir.glob("#{load_path}/*.rb").each do |file|
            require_dependency file
          end
        end
356 357 358
      end
    end

359 360 361 362 363 364 365
    # 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, this does nothing. Specify the default encoding in the Ruby
    # shebang line if you don't want UTF-8.
366
    def initialize_encoding
367
      $KCODE='u' if RUBY_VERSION < '1.9'
368 369
    end

370 371 372 373
    # 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.
374
    def initialize_database
375 376 377 378
      if configuration.frameworks.include?(:active_record)
        ActiveRecord::Base.configurations = configuration.database_configuration
        ActiveRecord::Base.establish_connection
      end
379
    end
380

381 382 383 384 385 386 387 388 389 390 391 392
    def initialize_cache
      unless defined?(RAILS_CACHE)
        silence_warnings { Object.const_set "RAILS_CACHE", ActiveSupport::Cache.lookup_store(configuration.cache_store) }
      end
    end

    def initialize_framework_caches
      if configuration.frameworks.include?(:action_controller)
        ActionController::Base.cache_store ||= RAILS_CACHE
      end
    end

P
Pratik Naik 已提交
393
    # If the RAILS_DEFAULT_LOGGER constant is already set, this initialization
394 395 396 397 398 399 400
    # routine does nothing. If the constant is not set, and Configuration#logger
    # is not +nil+, this also does nothing. Otherwise, a new logger instance
    # is created at Configuration#log_path, with a default log level of
    # Configuration#log_level.
    #
    # If the log could not be created, the log will be set to output to
    # +STDERR+, with a log level of +WARN+.
401
    def initialize_logger
402 403 404
      # if the environment has explicitly defined a logger, use it
      return if defined?(RAILS_DEFAULT_LOGGER)

405 406
      unless logger = configuration.logger
        begin
407 408
          logger = ActiveSupport::BufferedLogger.new(configuration.log_path)
          logger.level = ActiveSupport::BufferedLogger.const_get(configuration.log_level.to_s.upcase)
409 410 411
          if configuration.environment == "production"
            logger.auto_flushing = false
          end
412
        rescue StandardError => e
413 414
          logger = ActiveSupport::BufferedLogger.new(STDERR)
          logger.level = ActiveSupport::BufferedLogger::WARN
415 416 417 418 419
          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
420
      end
421

422
      silence_warnings { Object.const_set "RAILS_DEFAULT_LOGGER", logger }
423
    end
424

P
Pratik Naik 已提交
425
    # Sets the logger for Active Record, Action Controller, and Action Mailer
426 427
    # (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
P
Pratik Naik 已提交
428
    # RAILS_DEFAULT_LOGGER.
429
    def initialize_framework_logging
430 431 432
      for framework in ([ :active_record, :action_controller, :action_mailer ] & configuration.frameworks)
        framework.to_s.camelize.constantize.const_get("Base").logger ||= RAILS_DEFAULT_LOGGER
      end
J
Joshua Peek 已提交
433

434
      RAILS_CACHE.logger ||= RAILS_DEFAULT_LOGGER
435
    end
436

437
    # Sets +ActionController::Base#view_paths+ and +ActionMailer::Base#template_root+
438
    # (but only for those frameworks that are to be loaded). If the framework's
439
    # paths have already been set, it is not changed, otherwise it is
440
    # set to use Configuration#view_path.
441
    def initialize_framework_views
442
      view_path = ActionView::PathSet::Path.new(configuration.view_path, false)
443 444
      ActionMailer::Base.template_root ||= view_path if configuration.frameworks.include?(:action_mailer)
      ActionController::Base.view_paths = view_path if configuration.frameworks.include?(:action_controller) && ActionController::Base.view_paths.empty?
445 446
    end

P
Pratik Naik 已提交
447
    # If Action Controller is not one of the loaded frameworks (Configuration#frameworks)
448 449
    # this does nothing. Otherwise, it loads the routing definitions and sets up
    # loading module used to lazily load controllers (Configuration#controller_paths).
450 451
    def initialize_routing
      return unless configuration.frameworks.include?(:action_controller)
452
      ActionController::Routing.controller_paths = configuration.controller_paths
453
      ActionController::Routing::Routes.configuration_file = configuration.routes_configuration_file
454 455
      ActionController::Routing::Routes.reload
    end
456

457 458
    # Sets the dependency loading mechanism based on the value of
    # Configuration#cache_classes.
459
    def initialize_dependency_mechanism
460
      ActiveSupport::Dependencies.mechanism = configuration.cache_classes ? :require : :load
461
    end
462

463 464
    # Loads support for "whiny nil" (noisy warnings when methods are invoked
    # on +nil+ values) if Configuration#whiny_nils is true.
465 466 467
    def initialize_whiny_nils
      require('active_support/whiny_nil') if configuration.whiny_nils
    end
468

469
    def initialize_temporary_session_directory
470
      if configuration.frameworks.include?(:action_controller)
471
        session_path = "#{configuration.root_path}/tmp/sessions/"
472 473 474 475
        ActionController::Base.session_options[:tmpdir] = File.exist?(session_path) ? session_path : Dir::tmpdir
      end
    end

P
Pratik Naik 已提交
476
    # Sets the default value for Time.zone, and turns on ActiveRecord::Base#time_zone_aware_attributes.
477
    # If assigned value cannot be matched to a TimeZone, an exception will be raised.
478 479
    def initialize_time_zone
      if configuration.time_zone
480
        zone_default = Time.send!(:get_zone, configuration.time_zone)
481
        unless zone_default
P
Pratik Naik 已提交
482
          raise %{Value assigned to config.time_zone not recognized. Run "rake -D time" for a list of tasks for finding appropriate time zone names.}
483 484
        end
        Time.zone_default = zone_default
485 486 487 488 489 490 491
        if configuration.frameworks.include?(:active_record)
          ActiveRecord::Base.time_zone_aware_attributes = true
          ActiveRecord::Base.default_timezone = :utc
        end
      end
    end

492
    # Initializes framework-specific settings for each of the loaded frameworks
493 494
    # (Configuration#frameworks). The available settings map to the accessors
    # on each of the corresponding Base classes.
495
    def initialize_framework_settings
496 497
      configuration.frameworks.each do |framework|
        base_class = framework.to_s.camelize.constantize.const_get("Base")
498

499 500 501
        configuration.send(framework).each do |setting, value|
          base_class.send("#{setting}=", value)
        end
502
      end
503 504 505
      configuration.active_support.each do |setting, value|
        ActiveSupport.send("#{setting}=", value)
      end
506
    end
507 508

    # Fires the user-supplied after_initialize block (Configuration#after_initialize)
509
    def after_initialize
510
      if gems_dependencies_loaded
511 512 513
        configuration.after_initialize_blocks.each do |block|
          block.call
        end
514
      end
515
    end
516

517
    def load_application_initializers
518
      if gems_dependencies_loaded
519 520 521
        Dir["#{configuration.root_path}/config/initializers/**/*.rb"].sort.each do |initializer|
          load(initializer)
        end
522 523
      end
    end
524

525
    def prepare_dispatcher
526
      return unless configuration.frameworks.include?(:action_controller)
527 528 529 530
      require 'dispatcher' unless defined?(::Dispatcher)
      Dispatcher.define_dispatcher_callbacks(configuration.cache_classes)
      Dispatcher.new(RAILS_DEFAULT_LOGGER).send :run_callbacks, :prepare_dispatch
    end
531 532 533 534 535 536

    def disable_dependency_loading
      if configuration.cache_classes && !configuration.dependency_loading
        ActiveSupport::Dependencies.unhook!
      end
    end
537
  end
538

539 540 541 542 543 544
  # The Configuration class holds all the parameters for the Initializer and
  # ships with defaults that suites most Rails applications. But it's possible
  # to overwrite everything. Usually, you'll create an Configuration file
  # implicitly through the block running on the Initializer, but it's also
  # possible to create the Configuration instance in advance and pass it in
  # like this:
545 546 547
  #
  #   config = Rails::Configuration.new
  #   Rails::Initializer.run(:process, config)
548
  class Configuration
549 550 551
    # The application's base directory.
    attr_reader :root_path

P
Pratik Naik 已提交
552
    # A stub for setting options on ActionController::Base.
553
    attr_accessor :action_controller
554

P
Pratik Naik 已提交
555
    # A stub for setting options on ActionMailer::Base.
556
    attr_accessor :action_mailer
557

P
Pratik Naik 已提交
558
    # A stub for setting options on ActionView::Base.
559
    attr_accessor :action_view
560

P
Pratik Naik 已提交
561
    # A stub for setting options on ActiveRecord::Base.
562
    attr_accessor :active_record
563

P
Pratik Naik 已提交
564
    # A stub for setting options on ActiveResource::Base.
565 566
    attr_accessor :active_resource

P
Pratik Naik 已提交
567
    # A stub for setting options on ActiveSupport.
568 569
    attr_accessor :active_support

570 571 572
    # Whether or not classes should be cached (set to false if you want
    # application classes to be reloaded on each request)
    attr_accessor :cache_classes
573

574 575 576 577 578 579 580
    # The list of paths that should be searched for controllers. (Defaults
    # to <tt>app/controllers</tt> and <tt>components</tt>.)
    attr_accessor :controller_paths

    # The path to the database configuration file to use. (Defaults to
    # <tt>config/database.yml</tt>.)
    attr_accessor :database_configuration_file
J
Joshua Peek 已提交
581

582 583 584
    # The path to the routes configuration file to use. (Defaults to
    # <tt>config/routes.rb</tt>.)
    attr_accessor :routes_configuration_file
585

586 587 588
    # The list of rails framework components that should be loaded. (Defaults
    # to <tt>:active_record</tt>, <tt>:action_controller</tt>,
    # <tt>:action_view</tt>, <tt>:action_mailer</tt>, and
D
David Heinemeier Hansson 已提交
589
    # <tt>:active_resource</tt>).
590
    attr_accessor :frameworks
591

592 593 594
    # An array of additional paths to prepend to the load path. By default,
    # all +app+, +lib+, +vendor+ and mock paths are included in this list.
    attr_accessor :load_paths
595

596
    # An array of paths from which Rails will automatically load from only once.
597
    # All elements of this array must also be in +load_paths+.
598
    attr_accessor :load_once_paths
599

600 601 602 603 604
    # An array of paths from which Rails will eager load on boot if cache
    # classes is enabled. All elements of this array must also be in
    # +load_paths+.
    attr_accessor :eager_load_paths

605 606 607 608
    # The log level to use for the default Rails logger. In production mode,
    # this defaults to <tt>:info</tt>. In development mode, it defaults to
    # <tt>:debug</tt>.
    attr_accessor :log_level
609

610 611 612
    # The path to the log file to use. Defaults to log/#{environment}.log
    # (e.g. log/development.log or log/production.log).
    attr_accessor :log_path
613

614 615 616 617 618
    # The specific logger to use. By default, a logger will be created and
    # initialized using #log_path and #log_level, but a programmer may
    # specifically set the logger to use via this accessor and it will be
    # used directly.
    attr_accessor :logger
619

620 621 622
    # The specific cache store to use. By default, the ActiveSupport::Cache::Store will be used.
    attr_accessor :cache_store

623 624
    # The root of the application's views. (Defaults to <tt>app/views</tt>.)
    attr_accessor :view_path
625

626 627 628
    # Set to +true+ if you want to be warned (noisily) when you try to invoke
    # any method of +nil+. Set to +false+ for the standard Ruby behavior.
    attr_accessor :whiny_nils
629

630 631 632
    # The list of plugins to load. If this is set to <tt>nil</tt>, all plugins will
    # be loaded. If this is set to <tt>[]</tt>, no plugins will be loaded. Otherwise,
    # plugins will be loaded in the order specified.
633 634 635 636
    attr_reader :plugins
    def plugins=(plugins)
      @plugins = plugins.nil? ? nil : plugins.map { |p| p.to_sym }
    end
637

638 639 640
    # The path to the root of the plugins directory. By default, it is in
    # <tt>vendor/plugins</tt>.
    attr_accessor :plugin_paths
641

642 643 644 645 646
    # The classes that handle finding the desired plugins that you'd like to load for
    # your application. By default it is the Rails::Plugin::FileSystemLocator which finds
    # plugins to load in <tt>vendor/plugins</tt>. You can hook into gem location by subclassing
    # Rails::Plugin::Locator and adding it onto the list of <tt>plugin_locators</tt>.
    attr_accessor :plugin_locators
647 648

    # The class that handles loading each plugin. Defaults to Rails::Plugin::Loader, but
649 650 651
    # a sub class would have access to fine grained modification of the loading behavior. See
    # the implementation of Rails::Plugin::Loader for more details.
    attr_accessor :plugin_loader
J
Joshua Peek 已提交
652

653
    # Enables or disables plugin reloading.  You can get around this setting per plugin.
P
Pratik Naik 已提交
654 655
    # If <tt>reload_plugins?</tt> is false, add this to your plugin's <tt>init.rb</tt>
    # to make it reloadable:
656
    #
657
    #   ActiveSupport::Dependencies.load_once_paths.delete lib_path
658
    #
P
Pratik Naik 已提交
659 660
    # If <tt>reload_plugins?</tt> is true, add this to your plugin's <tt>init.rb</tt>
    # to only load it once:
661
    #
662
    #   ActiveSupport::Dependencies.load_once_paths << lib_path
663 664 665 666 667 668 669
    #
    attr_accessor :reload_plugins

    # Returns true if plugin reloading is enabled.
    def reload_plugins?
      !!@reload_plugins
    end
670

671 672 673 674 675 676 677 678 679 680 681
    # Enables or disables dependency loading during the request cycle. Setting
    # <tt>dependency_loading</tt> to true will allow new classes to be loaded
    # during a request. Setting it to false will disable this behavior.
    #
    # Those who want to run in a threaded environment should disable this
    # option and eager load or require all there classes on initialization.
    #
    # If <tt>cache_classes</tt> is disabled, dependency loaded will always be
    # on.
    attr_accessor :dependency_loading

682 683 684 685 686
    # An array of gems that this rails application depends on.  Rails will automatically load
    # these gems during installation, and allow you to install any missing gems with:
    #
    #   rake gems:install
    #
R
Rick Olson 已提交
687
    # You can add gems with the #gem method.
688 689 690 691 692 693 694 695 696 697 698 699
    attr_accessor :gems

    # Adds a single Gem dependency to the rails application.
    #
    #   # gem 'aws-s3', '>= 0.4.0'
    #   # require 'aws/s3'
    #   config.gem 'aws-s3', :lib => 'aws/s3', :version => '>= 0.4.0', \
    #     :source => "http://code.whytheluckystiff.net"
    #
    def gem(name, options = {})
      @gems << Rails::GemDependency.new(name, options)
    end
J
Joshua Peek 已提交
700

701 702 703 704 705 706 707 708 709
    # Deprecated options:
    def breakpoint_server(_ = nil)
      $stderr.puts %(
      *******************************************************************
      * config.breakpoint_server has been deprecated and has no effect. *
      *******************************************************************
      )
    end
    alias_method :breakpoint_server=, :breakpoint_server
710

P
Pratik Naik 已提交
711 712 713
    # Sets the default +time_zone+.  Setting this will enable +time_zone+
    # awareness for Active Record models and set the Active Record default
    # timezone to <tt>:utc</tt>.
714 715
    attr_accessor :time_zone

716 717
    # Create a new Configuration instance, initialized with the default
    # values.
718
    def initialize
719 720
      set_root_path!

721 722
      self.frameworks                   = default_frameworks
      self.load_paths                   = default_load_paths
723
      self.load_once_paths              = default_load_once_paths
724
      self.eager_load_paths             = default_eager_load_paths
725 726 727 728 729
      self.log_path                     = default_log_path
      self.log_level                    = default_log_level
      self.view_path                    = default_view_path
      self.controller_paths             = default_controller_paths
      self.cache_classes                = default_cache_classes
730
      self.dependency_loading           = default_dependency_loading
731
      self.whiny_nils                   = default_whiny_nils
732
      self.plugins                      = default_plugins
733
      self.plugin_paths                 = default_plugin_paths
734
      self.plugin_locators              = default_plugin_locators
735
      self.plugin_loader                = default_plugin_loader
736
      self.database_configuration_file  = default_database_configuration_file
737
      self.routes_configuration_file    = default_routes_configuration_file
738
      self.gems                         = default_gems
739

740
      for framework in default_frameworks
741
        self.send("#{framework}=", Rails::OrderedOptions.new)
742
      end
743
      self.active_support = Rails::OrderedOptions.new
744
    end
745

746 747 748 749 750 751 752 753 754 755 756 757 758 759 760
    # Set the root_path to RAILS_ROOT and canonicalize it.
    def set_root_path!
      raise 'RAILS_ROOT is not set' unless defined?(::RAILS_ROOT)
      raise 'RAILS_ROOT is not a directory' unless File.directory?(::RAILS_ROOT)

      @root_path =
        # Pathname is incompatible with Windows, but Windows doesn't have
        # real symlinks so File.expand_path is safe.
        if RUBY_PLATFORM =~ /(:?mswin|mingw)/
          File.expand_path(::RAILS_ROOT)

        # Otherwise use Pathname#realpath which respects symlinks.
        else
          Pathname.new(::RAILS_ROOT).realpath.to_s
        end
J
Joshua Peek 已提交
761

762
      Object.const_set(:RELATIVE_RAILS_ROOT, ::RAILS_ROOT.dup) unless defined?(::RELATIVE_RAILS_ROOT)
763
      ::RAILS_ROOT.replace @root_path
764 765
    end

766 767 768
    # Loads and returns the contents of the #database_configuration_file. The
    # contents of the file are processed via ERB before being sent through
    # YAML::load.
769
    def database_configuration
770
      YAML::load(ERB.new(IO.read(database_configuration_file)).result)
771
    end
772

P
Pratik Naik 已提交
773
    # The path to the current environment's file (<tt>development.rb</tt>, etc.). By
774
    # default the file is at <tt>config/environments/#{environment}.rb</tt>.
775
    def environment_path
776
      "#{root_path}/config/environments/#{environment}.rb"
777
    end
J
Jamis Buck 已提交
778

779
    # Return the currently selected environment. By default, it returns the
P
Pratik Naik 已提交
780
    # value of the RAILS_ENV constant.
781 782 783
    def environment
      ::RAILS_ENV
    end
784

785
    # Adds a block which will be executed after rails has been fully initialized.
786
    # Useful for per-environment configuration which depends on the framework being
787 788
    # fully initialized.
    def after_initialize(&after_initialize_block)
789
      after_initialize_blocks << after_initialize_block if after_initialize_block
790
    end
791

792 793 794
    # Returns the blocks added with Configuration#after_initialize
    def after_initialize_blocks
      @after_initialize_blocks ||= []
795
    end
796

N
Nicholas Seckar 已提交
797 798
    # Add a preparation callback that will run before every request in development
    # mode, or before the first request in production.
799
    #
N
Nicholas Seckar 已提交
800 801
    # See Dispatcher#to_prepare.
    def to_prepare(&callback)
J
Joshua Peek 已提交
802
      after_initialize do
803 804 805
        require 'dispatcher' unless defined?(::Dispatcher)
        Dispatcher.to_prepare(&callback)
      end
N
Nicholas Seckar 已提交
806
    end
807

808 809 810 811
    def builtin_directories
      # Include builtins only in the development environment.
      (environment == 'development') ? Dir["#{RAILTIES_PATH}/builtin/*/"] : []
    end
812

813
    def framework_paths
814 815
      paths = %w(railties railties/lib activesupport/lib)
      paths << 'actionpack/lib' if frameworks.include? :action_controller or frameworks.include? :action_view
J
Joshua Peek 已提交
816

817 818 819
      [:active_record, :action_mailer, :active_resource, :action_web_service].each do |framework|
        paths << "#{framework.to_s.gsub('_', '')}/lib" if frameworks.include? framework
      end
J
Joshua Peek 已提交
820

821
      paths.map { |dir| "#{framework_root_path}/#{dir}" }.select { |dir| File.directory?(dir) }
822
    end
823

824
    private
825 826 827 828
      def framework_root_path
        defined?(::RAILS_FRAMEWORK_ROOT) ? ::RAILS_FRAMEWORK_ROOT : "#{root_path}/vendor/rails"
      end

829
      def default_frameworks
830
        [ :active_record, :action_controller, :action_view, :action_mailer, :active_resource ]
831
      end
832

833
      def default_load_paths
834
        paths = []
J
Joshua Peek 已提交
835

836 837
        # Add the old mock paths only if the directories exists
        paths.concat(Dir["#{root_path}/test/mocks/#{environment}"]) if File.exists?("#{root_path}/test/mocks/#{environment}")
838

N
Nicholas Seckar 已提交
839 840
        # Add the app's controller directory
        paths.concat(Dir["#{root_path}/app/controllers/"])
841

842
        # Then components subdirectories.
843
        paths.concat(Dir["#{root_path}/components/[_a-z]*"])
844 845 846

        # Followed by the standard includes.
        paths.concat %w(
847 848
          app
          app/models
849 850 851
          app/controllers
          app/helpers
          app/services
852 853 854 855
          components
          config
          lib
          vendor
856
        ).map { |dir| "#{root_path}/#{dir}" }.select { |dir| File.directory?(dir) }
857

858
        paths.concat builtin_directories
859
      end
860

861
      # Doesn't matter since plugins aren't in load_paths yet.
862
      def default_load_once_paths
863
        []
864
      end
865

866 867 868 869 870 871 872 873
      def default_eager_load_paths
        %w(
          app/models
          app/controllers
          app/helpers
        ).map { |dir| "#{root_path}/#{dir}" }.select { |dir| File.directory?(dir) }
      end

874
      def default_log_path
875
        File.join(root_path, 'log', "#{environment}.log")
876
      end
877

878
      def default_log_level
879
        environment == 'production' ? :info : :debug
880
      end
881

882
      def default_database_configuration_file
883
        File.join(root_path, 'config', 'database.yml')
884
      end
885

886 887 888 889
      def default_routes_configuration_file
        File.join(root_path, 'config', 'routes.rb')
      end

890
      def default_view_path
891
        File.join(root_path, 'app', 'views')
892
      end
893

894
      def default_controller_paths
895
        paths = [File.join(root_path, 'app', 'controllers')]
896 897
        paths.concat builtin_directories
        paths
898
      end
899

900 901
      def default_dependency_loading
        true
902
      end
903

904 905 906
      def default_cache_classes
        false
      end
907

908 909 910
      def default_whiny_nils
        false
      end
911

912
      def default_plugins
913
        nil
914 915
      end

916 917 918
      def default_plugin_paths
        ["#{root_path}/vendor/plugins"]
      end
919

920
      def default_plugin_locators
921 922 923
        locators = []
        locators << Plugin::GemLocator if defined? Gem
        locators << Plugin::FileSystemLocator
924
      end
925

926 927 928
      def default_plugin_loader
        Plugin::Loader
      end
J
Joshua Peek 已提交
929

930 931 932 933 934 935 936
      def default_cache_store
        if File.exist?("#{root_path}/tmp/cache/")
          [ :file_store, "#{root_path}/tmp/cache/" ]
        else
          :memory_store
        end
      end
J
Joshua Peek 已提交
937

938 939 940
      def default_gems
        []
      end
941
  end
942
end
943

944
# Needs to be duplicated from Active Support since its needed before Active
945
# Support is available. Here both Options and Hash are namespaced to prevent
P
Pratik Naik 已提交
946
# conflicts with other implementations AND with the classes residing in Active Support.
947 948 949 950
class Rails::OrderedOptions < Array #:nodoc:
  def []=(key, value)
    key = key.to_sym

951 952 953 954 955 956 957 958
    if pair = find_pair(key)
      pair.pop
      pair << value
    else
      self << [key, value]
    end
  end

959
  def [](key)
960 961
    pair = find_pair(key.to_sym)
    pair ? pair.last : nil
962 963 964 965 966 967 968 969 970
  end

  def method_missing(name, *args)
    if name.to_s =~ /(.*)=$/
      self[$1.to_sym] = args.first
    else
      self[name]
    end
  end
971 972 973 974 975 976

  private
    def find_pair(key)
      self.each { |i| return i if i.first == key }
      return false
    end
977
end