initializer.rb 31.4 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
101
    # incuring 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

      # Flag initialized
      Rails.initialized = true
173
    end
174 175 176 177

    # 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.
178
    def check_ruby_version
179 180 181
      require 'ruby_version_check'
    end

182
    # If Rails is vendored and RubyGems is available, install stub GemSpecs
P
Pratik Naik 已提交
183 184
    # for Rails, Active Support, Active Record, Action Pack, Action Mailer, and
    # Active Resource. This allows Gem plugins to depend on Rails even when
185 186
    # the Gem version of Rails shouldn't be loaded.
    def install_gem_spec_stubs
187
      unless Rails.respond_to?(:vendor_rails?)
P
Pratik Naik 已提交
188
        abort %{Your config/boot.rb is outdated: Run "rake rails:update".}
189 190
      end

191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
      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

206 207
    # Set the <tt>$LOAD_PATH</tt> based on the value of
    # Configuration#load_paths. Duplicates are removed.
208
    def set_load_path
209 210
      load_paths = configuration.load_paths + configuration.framework_paths
      load_paths.reverse_each { |dir| $LOAD_PATH.unshift(dir) if File.directory?(dir) }
211 212
      $LOAD_PATH.uniq!
    end
213

214 215
    # Set the paths from which Rails will automatically load source files, and
    # the load_once paths.
216
    def set_autoload_paths
217 218
      ActiveSupport::Dependencies.load_paths = configuration.load_paths.uniq
      ActiveSupport::Dependencies.load_once_paths = configuration.load_once_paths.uniq
219

220
      extra = ActiveSupport::Dependencies.load_once_paths - ActiveSupport::Dependencies.load_paths
221 222
      unless extra.empty?
        abort <<-end_error
223
          load_once_paths must be a subset of the load_paths.
224 225 226
          Extra items in load_once_paths: #{extra * ','}
        end_error
      end
227

228 229
      # Freeze the arrays so future modifications will fail rather than do nothing mysteriously
      configuration.load_once_paths.freeze
230
    end
231

232
    # Requires all frameworks specified by the Configuration#frameworks
P
Pratik Naik 已提交
233 234
    # list. By default, all frameworks (Active Record, Active Support,
    # Action Pack, Action Mailer, and Active Resource) are loaded.
235 236
    def require_frameworks
      configuration.frameworks.each { |framework| require(framework.to_s) }
237 238 239
    rescue LoadError => e
      # re-raise because Mongrel would swallow it
      raise e.to_s
240
    end
241

242 243
    # Add the load paths used by support functions such as the info controller
    def add_support_load_paths
244
    end
245

246
    # Adds all load paths from plugins to the global set of load paths, so that
247
    # code from plugins can be required (explicitly or automatically via ActiveSupport::Dependencies).
248 249 250 251
    def add_plugin_load_paths
      plugin_loader.add_plugin_load_paths
    end

252 253 254
    def add_gem_load_paths
      unless @configuration.gems.empty?
        require "rubygems"
255
        @configuration.gems.each { |gem| gem.add_load_paths }
256 257 258 259
      end
    end

    def load_gems
260
      @configuration.gems.each { |gem| gem.load }
261 262 263 264 265 266 267 268
    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
269 270 271 272 273 274 275 276 277 278
          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
279 280 281 282
        end
      else
        @gems_dependencies_loaded = true
      end
283 284
    end

285 286 287
    # 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 已提交
288
    #   config.plugin_paths = ["#{RAILS_ROOT}/lib/plugins", "#{RAILS_ROOT}/vendor/plugins"]
289
    #
290 291
    # 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)
292
    # * <tt>init.rb</tt> is evaluated, if present
293 294
    #
    # After all plugins are loaded, duplicates are removed from the load path.
295 296
    # 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
297
    # order.
298 299 300
    #
    # 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 已提交
301
    def load_plugins
302 303 304 305 306
      plugin_loader.load_plugins
    end

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

309
    # Loads the environment specified by Configuration#environment_path, which
310
    # is typically one of development, test, or production.
311 312
    def load_environment
      silence_warnings do
313 314
        return if @environment_loaded
        @environment_loaded = true
J
Joshua Peek 已提交
315

316
        config = configuration
317
        constants = self.class.constants
J
Joshua Peek 已提交
318

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

321 322 323
        (self.class.constants - constants).each do |const|
          Object.const_set(const, self.class.const_get(const))
        end
324
      end
325
    end
326 327

    def load_observers
328
      if gems_dependencies_loaded && configuration.frameworks.include?(:active_record)
329
        ActiveRecord::Base.instantiate_observers
330
      end
331 332
    end

333 334 335 336 337 338 339
    # 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.
340
    def initialize_encoding
341
      $KCODE='u' if RUBY_VERSION < '1.9'
342 343
    end

344 345 346 347
    # 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.
348
    def initialize_database
349 350 351 352
      if configuration.frameworks.include?(:active_record)
        ActiveRecord::Base.configurations = configuration.database_configuration
        ActiveRecord::Base.establish_connection
      end
353
    end
354

355 356 357 358 359 360 361 362 363 364 365 366
    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 已提交
367
    # If the RAILS_DEFAULT_LOGGER constant is already set, this initialization
368 369 370 371 372 373 374
    # 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+.
375
    def initialize_logger
376 377 378
      # if the environment has explicitly defined a logger, use it
      return if defined?(RAILS_DEFAULT_LOGGER)

379 380
      unless logger = configuration.logger
        begin
381 382
          logger = ActiveSupport::BufferedLogger.new(configuration.log_path)
          logger.level = ActiveSupport::BufferedLogger.const_get(configuration.log_level.to_s.upcase)
383 384 385 386
          if configuration.environment == "production"
            logger.auto_flushing = false
            logger.set_non_blocking_io
          end
387
        rescue StandardError => e
388 389
          logger = ActiveSupport::BufferedLogger.new(STDERR)
          logger.level = ActiveSupport::BufferedLogger::WARN
390 391 392 393 394
          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
395
      end
396

397
      silence_warnings { Object.const_set "RAILS_DEFAULT_LOGGER", logger }
398
    end
399

P
Pratik Naik 已提交
400
    # Sets the logger for Active Record, Action Controller, and Action Mailer
401 402
    # (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 已提交
403
    # RAILS_DEFAULT_LOGGER.
404
    def initialize_framework_logging
405 406 407
      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 已提交
408

409
      RAILS_CACHE.logger ||= RAILS_DEFAULT_LOGGER
410
    end
411

412
    # Sets +ActionController::Base#view_paths+ and +ActionMailer::Base#template_root+
413
    # (but only for those frameworks that are to be loaded). If the framework's
414
    # paths have already been set, it is not changed, otherwise it is
415
    # set to use Configuration#view_path.
416
    def initialize_framework_views
417
      ActionView::PathSet::Path.eager_load_templates! if configuration.cache_classes
418 419
      ActionMailer::Base.template_root ||= configuration.view_path  if configuration.frameworks.include?(:action_mailer)
      ActionController::Base.view_paths = [configuration.view_path] if configuration.frameworks.include?(:action_controller) && ActionController::Base.view_paths.empty?
420 421
    end

P
Pratik Naik 已提交
422
    # If Action Controller is not one of the loaded frameworks (Configuration#frameworks)
423 424
    # this does nothing. Otherwise, it loads the routing definitions and sets up
    # loading module used to lazily load controllers (Configuration#controller_paths).
425 426
    def initialize_routing
      return unless configuration.frameworks.include?(:action_controller)
427
      ActionController::Routing.controller_paths = configuration.controller_paths
428
      ActionController::Routing::Routes.configuration_file = configuration.routes_configuration_file
429 430
      ActionController::Routing::Routes.reload
    end
431

432 433
    # Sets the dependency loading mechanism based on the value of
    # Configuration#cache_classes.
434
    def initialize_dependency_mechanism
435
      ActiveSupport::Dependencies.mechanism = configuration.cache_classes ? :require : :load
436
    end
437

438 439
    # Loads support for "whiny nil" (noisy warnings when methods are invoked
    # on +nil+ values) if Configuration#whiny_nils is true.
440 441 442
    def initialize_whiny_nils
      require('active_support/whiny_nil') if configuration.whiny_nils
    end
443

444
    def initialize_temporary_session_directory
445
      if configuration.frameworks.include?(:action_controller)
446
        session_path = "#{configuration.root_path}/tmp/sessions/"
447 448 449 450
        ActionController::Base.session_options[:tmpdir] = File.exist?(session_path) ? session_path : Dir::tmpdir
      end
    end

P
Pratik Naik 已提交
451
    # Sets the default value for Time.zone, and turns on ActiveRecord::Base#time_zone_aware_attributes.
452
    # If assigned value cannot be matched to a TimeZone, an exception will be raised.
453 454
    def initialize_time_zone
      if configuration.time_zone
455
        zone_default = Time.send!(:get_zone, configuration.time_zone)
456
        unless zone_default
P
Pratik Naik 已提交
457
          raise %{Value assigned to config.time_zone not recognized. Run "rake -D time" for a list of tasks for finding appropriate time zone names.}
458 459
        end
        Time.zone_default = zone_default
460 461 462 463 464 465 466
        if configuration.frameworks.include?(:active_record)
          ActiveRecord::Base.time_zone_aware_attributes = true
          ActiveRecord::Base.default_timezone = :utc
        end
      end
    end

467
    # Initializes framework-specific settings for each of the loaded frameworks
468 469
    # (Configuration#frameworks). The available settings map to the accessors
    # on each of the corresponding Base classes.
470
    def initialize_framework_settings
471 472
      configuration.frameworks.each do |framework|
        base_class = framework.to_s.camelize.constantize.const_get("Base")
473

474 475 476
        configuration.send(framework).each do |setting, value|
          base_class.send("#{setting}=", value)
        end
477
      end
478 479 480
      configuration.active_support.each do |setting, value|
        ActiveSupport.send("#{setting}=", value)
      end
481
    end
482 483

    # Fires the user-supplied after_initialize block (Configuration#after_initialize)
484
    def after_initialize
485
      if gems_dependencies_loaded
486 487 488
        configuration.after_initialize_blocks.each do |block|
          block.call
        end
489
      end
490
    end
491

492
    def load_application_initializers
493
      if gems_dependencies_loaded
494 495 496
        Dir["#{configuration.root_path}/config/initializers/**/*.rb"].sort.each do |initializer|
          load(initializer)
        end
497 498
      end
    end
499

500 501 502 503 504
    def prepare_dispatcher
      require 'dispatcher' unless defined?(::Dispatcher)
      Dispatcher.define_dispatcher_callbacks(configuration.cache_classes)
      Dispatcher.new(RAILS_DEFAULT_LOGGER).send :run_callbacks, :prepare_dispatch
    end
505
  end
506

507 508 509 510 511 512
  # 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:
513 514 515
  #
  #   config = Rails::Configuration.new
  #   Rails::Initializer.run(:process, config)
516
  class Configuration
517 518 519
    # The application's base directory.
    attr_reader :root_path

P
Pratik Naik 已提交
520
    # A stub for setting options on ActionController::Base.
521
    attr_accessor :action_controller
522

P
Pratik Naik 已提交
523
    # A stub for setting options on ActionMailer::Base.
524
    attr_accessor :action_mailer
525

P
Pratik Naik 已提交
526
    # A stub for setting options on ActionView::Base.
527
    attr_accessor :action_view
528

P
Pratik Naik 已提交
529
    # A stub for setting options on ActiveRecord::Base.
530
    attr_accessor :active_record
531

P
Pratik Naik 已提交
532
    # A stub for setting options on ActiveRecord::Base.
533 534
    attr_accessor :active_resource

P
Pratik Naik 已提交
535
    # A stub for setting options on ActiveSupport.
536 537
    attr_accessor :active_support

538 539 540
    # 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
541

542 543 544 545 546 547 548
    # 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 已提交
549

550 551 552
    # The path to the routes configuration file to use. (Defaults to
    # <tt>config/routes.rb</tt>.)
    attr_accessor :routes_configuration_file
553

554 555 556
    # 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 已提交
557
    # <tt>:active_resource</tt>).
558
    attr_accessor :frameworks
559

560 561 562
    # 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
563

564
    # An array of paths from which Rails will automatically load from only once.
565
    # All elements of this array must also be in +load_paths+.
566
    attr_accessor :load_once_paths
567

568 569 570 571
    # 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
572

573 574 575
    # 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
576

577 578 579 580 581
    # 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
582

583 584 585
    # The specific cache store to use. By default, the ActiveSupport::Cache::Store will be used.
    attr_accessor :cache_store

586 587
    # The root of the application's views. (Defaults to <tt>app/views</tt>.)
    attr_accessor :view_path
588

589 590 591
    # 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
592

593 594 595
    # 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.
596 597 598 599
    attr_reader :plugins
    def plugins=(plugins)
      @plugins = plugins.nil? ? nil : plugins.map { |p| p.to_sym }
    end
600

601 602 603
    # The path to the root of the plugins directory. By default, it is in
    # <tt>vendor/plugins</tt>.
    attr_accessor :plugin_paths
604

605 606 607 608 609
    # 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
610 611

    # The class that handles loading each plugin. Defaults to Rails::Plugin::Loader, but
612 613 614
    # 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 已提交
615

616
    # Enables or disables plugin reloading.  You can get around this setting per plugin.
P
Pratik Naik 已提交
617 618
    # If <tt>reload_plugins?</tt> is false, add this to your plugin's <tt>init.rb</tt>
    # to make it reloadable:
619
    #
620
    #   ActiveSupport::Dependencies.load_once_paths.delete lib_path
621
    #
P
Pratik Naik 已提交
622 623
    # If <tt>reload_plugins?</tt> is true, add this to your plugin's <tt>init.rb</tt>
    # to only load it once:
624
    #
625
    #   ActiveSupport::Dependencies.load_once_paths << lib_path
626 627 628 629 630 631 632
    #
    attr_accessor :reload_plugins

    # Returns true if plugin reloading is enabled.
    def reload_plugins?
      !!@reload_plugins
    end
633 634 635 636 637 638

    # 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 已提交
639
    # You can add gems with the #gem method.
640 641 642 643 644 645 646 647 648 649 650 651
    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 已提交
652

653 654 655 656 657 658 659 660 661
    # 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
662

P
Pratik Naik 已提交
663 664 665
    # 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>.
666 667
    attr_accessor :time_zone

668 669
    # Create a new Configuration instance, initialized with the default
    # values.
670
    def initialize
671 672
      set_root_path!

673 674
      self.frameworks                   = default_frameworks
      self.load_paths                   = default_load_paths
675
      self.load_once_paths              = default_load_once_paths
676 677 678 679 680 681
      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
      self.whiny_nils                   = default_whiny_nils
682
      self.plugins                      = default_plugins
683
      self.plugin_paths                 = default_plugin_paths
684
      self.plugin_locators              = default_plugin_locators
685
      self.plugin_loader                = default_plugin_loader
686
      self.database_configuration_file  = default_database_configuration_file
687
      self.routes_configuration_file    = default_routes_configuration_file
688
      self.gems                         = default_gems
689

690
      for framework in default_frameworks
691
        self.send("#{framework}=", Rails::OrderedOptions.new)
692
      end
693
      self.active_support = Rails::OrderedOptions.new
694
    end
695

696 697 698 699 700 701 702 703 704 705 706 707 708 709 710
    # 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 已提交
711

712
      Object.const_set(:RELATIVE_RAILS_ROOT, ::RAILS_ROOT.dup) unless defined?(::RELATIVE_RAILS_ROOT)
713
      ::RAILS_ROOT.replace @root_path
714 715
    end

716 717 718
    # 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.
719
    def database_configuration
720
      YAML::load(ERB.new(IO.read(database_configuration_file)).result)
721
    end
722

P
Pratik Naik 已提交
723
    # The path to the current environment's file (<tt>development.rb</tt>, etc.). By
724
    # default the file is at <tt>config/environments/#{environment}.rb</tt>.
725
    def environment_path
726
      "#{root_path}/config/environments/#{environment}.rb"
727
    end
J
Jamis Buck 已提交
728

729
    # Return the currently selected environment. By default, it returns the
P
Pratik Naik 已提交
730
    # value of the RAILS_ENV constant.
731 732 733
    def environment
      ::RAILS_ENV
    end
734

735
    # Adds a block which will be executed after rails has been fully initialized.
736
    # Useful for per-environment configuration which depends on the framework being
737 738
    # fully initialized.
    def after_initialize(&after_initialize_block)
739
      after_initialize_blocks << after_initialize_block if after_initialize_block
740
    end
741

742 743 744
    # Returns the blocks added with Configuration#after_initialize
    def after_initialize_blocks
      @after_initialize_blocks ||= []
745
    end
746

N
Nicholas Seckar 已提交
747 748
    # Add a preparation callback that will run before every request in development
    # mode, or before the first request in production.
749
    #
N
Nicholas Seckar 已提交
750 751
    # See Dispatcher#to_prepare.
    def to_prepare(&callback)
J
Joshua Peek 已提交
752
      after_initialize do
753 754 755
        require 'dispatcher' unless defined?(::Dispatcher)
        Dispatcher.to_prepare(&callback)
      end
N
Nicholas Seckar 已提交
756
    end
757

758 759 760 761
    def builtin_directories
      # Include builtins only in the development environment.
      (environment == 'development') ? Dir["#{RAILTIES_PATH}/builtin/*/"] : []
    end
762

763
    def framework_paths
764 765
      paths = %w(railties railties/lib activesupport/lib)
      paths << 'actionpack/lib' if frameworks.include? :action_controller or frameworks.include? :action_view
J
Joshua Peek 已提交
766

767 768 769
      [: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 已提交
770

771
      paths.map { |dir| "#{framework_root_path}/#{dir}" }.select { |dir| File.directory?(dir) }
772
    end
773

774
    private
775 776 777 778
      def framework_root_path
        defined?(::RAILS_FRAMEWORK_ROOT) ? ::RAILS_FRAMEWORK_ROOT : "#{root_path}/vendor/rails"
      end

779
      def default_frameworks
780
        [ :active_record, :action_controller, :action_view, :action_mailer, :active_resource ]
781
      end
782

783
      def default_load_paths
784
        paths = []
J
Joshua Peek 已提交
785

786 787
        # 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}")
788

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

792
        # Then components subdirectories.
793
        paths.concat(Dir["#{root_path}/components/[_a-z]*"])
794 795 796

        # Followed by the standard includes.
        paths.concat %w(
797 798
          app
          app/models
799 800 801
          app/controllers
          app/helpers
          app/services
802 803 804 805
          components
          config
          lib
          vendor
806
        ).map { |dir| "#{root_path}/#{dir}" }.select { |dir| File.directory?(dir) }
807

808
        paths.concat builtin_directories
809
      end
810

811
      # Doesn't matter since plugins aren't in load_paths yet.
812
      def default_load_once_paths
813
        []
814
      end
815 816

      def default_log_path
817
        File.join(root_path, 'log', "#{environment}.log")
818
      end
819

820
      def default_log_level
821
        environment == 'production' ? :info : :debug
822
      end
823

824
      def default_database_configuration_file
825
        File.join(root_path, 'config', 'database.yml')
826
      end
827

828 829 830 831
      def default_routes_configuration_file
        File.join(root_path, 'config', 'routes.rb')
      end

832
      def default_view_path
833
        File.join(root_path, 'app', 'views')
834
      end
835

836
      def default_controller_paths
837
        paths = [File.join(root_path, 'app', 'controllers')]
838 839
        paths.concat builtin_directories
        paths
840
      end
841

842 843 844
      def default_dependency_mechanism
        :load
      end
845

846 847 848
      def default_cache_classes
        false
      end
849

850 851 852
      def default_whiny_nils
        false
      end
853

854
      def default_plugins
855
        nil
856 857
      end

858 859 860
      def default_plugin_paths
        ["#{root_path}/vendor/plugins"]
      end
861

862
      def default_plugin_locators
863 864 865
        locators = []
        locators << Plugin::GemLocator if defined? Gem
        locators << Plugin::FileSystemLocator
866
      end
867

868 869 870
      def default_plugin_loader
        Plugin::Loader
      end
J
Joshua Peek 已提交
871

872 873 874 875 876 877 878
      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 已提交
879

880 881 882
      def default_gems
        []
      end
883
  end
884
end
885

886
# Needs to be duplicated from Active Support since its needed before Active
887
# Support is available. Here both Options and Hash are namespaced to prevent
P
Pratik Naik 已提交
888
# conflicts with other implementations AND with the classes residing in Active Support.
889 890 891 892
class Rails::OrderedOptions < Array #:nodoc:
  def []=(key, value)
    key = key.to_sym

893 894 895 896 897 898 899 900
    if pair = find_pair(key)
      pair.pop
      pair << value
    else
      self << [key, value]
    end
  end

901
  def [](key)
902 903
    pair = find_pair(key.to_sym)
    pair ? pair.last : nil
904 905 906 907 908 909 910 911 912
  end

  def method_missing(name, *args)
    if name.to_s =~ /(.*)=$/
      self[$1.to_sym] = args.first
    else
      self[name]
    end
  end
913 914 915 916 917 918

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