initializer.rb 6.2 KB
Newer Older
1 2 3 4 5
require 'logger'

RAILS_ENV = ENV['RAILS_ENV'] || 'development'

module Rails
6 7 8 9 10 11 12 13 14 15 16 17 18
  # 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:
  #
  #   Rails::Initializer.run
  #
  # But normally it's more interesting to pass in a custom configuration through the block running:
  #
  #   Rails::Initializer.run do |config|
  #     config.frameworks -= [ :action_web_service ]
  #   end
  #
  # This will use the default configuration options from Rails::Configuration, but allow for overwriting on select areas.
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
  class Initializer
    attr_reader :configuration
    
    def self.run(command = :process, configuration = Configuration.new)
      yield configuration if block_given?
      new(configuration).send(command)
    end
    
    def initialize(configuration)
      @configuration = configuration
    end
    
    def process
      set_load_path

      require_frameworks
      require_environment

      initialize_database
      initialize_logger
      initialize_framework_logging
40
      initialize_framework_views
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
      initialize_routing
    end
    
    def set_load_path
      configuration.load_paths.reverse.each { |dir| $LOAD_PATH.unshift(dir) if File.directory?(dir) }
      $LOAD_PATH.uniq!
    end
    
    def require_frameworks
      configuration.frameworks.each { |framework| require(framework.to_s) }
    end
    
    def require_environment
      require_dependency(configuration.environment_file)
    end
    
    def initialize_database
      return unless configuration.frameworks.include?(:active_record)
      ActiveRecord::Base.configurations = configuration.database_configuration
      ActiveRecord::Base.establish_connection
    end
    
    def initialize_logger
64 65 66
      # if the environment has explicitly defined a logger, use it
      return if defined?(RAILS_DEFAULT_LOGGER)

67 68 69 70 71 72 73 74 75 76 77 78
      begin
        logger = Logger.new(configuration.log_path)
        logger.level = configuration.log_level
      rescue StandardError
        logger = Logger.new(STDERR)
        logger.level = Logger::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
      
79
      old_verbose, $VERBOSE = $VERBOSE, nil
80
      Object.const_set "RAILS_DEFAULT_LOGGER", logger
81
      $VERBOSE = old_verbose
82 83 84
    end
    
    def initialize_framework_logging
85
      # TODO: Only do logging for frameworks loaded
86 87 88 89
      [ActiveRecord, ActionController, ActionMailer].each { |mod| mod::Base.logger ||= RAILS_DEFAULT_LOGGER }        
    end
    
    def initialize_framework_views
90
      # TODO: Only do view setting for frameworks loaded
91 92 93 94 95 96 97 98 99 100
      [ActionController, ActionMailer].each { |mod| mod::Base.template_root ||= configuration.view_path }        
    end

    def initialize_routing
      return unless configuration.frameworks.include?(:action_controller)
      ActionController::Routing::Routes.reload
      Object.const_set "Controllers", Dependencies::LoadingModule.root(*configuration.controller_paths)
    end
  end
  
101 102 103 104 105 106 107
  # 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:
  #
  #   config = Rails::Configuration.new
  #   Rails::Initializer.run(:process, config)
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
  class Configuration
    attr_accessor :frameworks, :load_paths, :log_level, :log_path, :database_configuration_file, :view_path, :controller_paths
    
    def initialize
      self.frameworks       = default_frameworks
      self.load_paths       = default_load_paths
      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.database_configuration_file  = default_database_configuration_file
    end
    
    def database_configuration
      YAML::load(ERB.new((IO.read(database_configuration_file))).result)
    end
    
    def environment_file
      "environments/#{environment}"
    end
    
    def environment
      ::RAILS_ENV
    end
    
    private
      def default_frameworks
        [ :active_support, :active_record, :action_controller, :action_mailer, :action_web_service ]
      end
    
      def default_load_paths
D
David Heinemeier Hansson 已提交
139
        paths = ["#{RAILS_ROOT}/test/mocks/#{environment}"]
140 141

        # Then model subdirectories.
142
        # TODO: Don't include .rb models as load paths
143 144 145 146
        paths.concat(Dir["#{RAILS_ROOT}/app/models/[_a-z]*"])
        paths.concat(Dir["#{RAILS_ROOT}/components/[_a-z]*"])

        # Followed by the standard includes.
147
        # TODO: Don't include dirs for frameworks that are not used
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
        paths.concat %w(
          app 
          app/models 
          app/controllers 
          app/helpers 
          app/apis 
          components 
          config 
          lib 
          vendor 
          vendor/rails/railties
          vendor/rails/railties/lib
          vendor/rails/actionpack/lib
          vendor/rails/activesupport/lib
          vendor/rails/activerecord/lib
          vendor/rails/actionmailer/lib
          vendor/rails/actionwebservice/lib
        ).map { |dir| "#{RAILS_ROOT}/#{dir}" }.select { |dir| File.directory?(dir) }
      end

      def default_log_path
        File.join(RAILS_ROOT, 'log', "#{environment}.log")
      end
      
      def default_log_level
        environment == 'production' ? Logger::INFO : Logger::DEBUG
      end
      
      def default_database_configuration_file
        File.join(RAILS_ROOT, 'config', 'database.yml')
      end
      
      def default_view_path
        File.join(RAILS_ROOT, 'app', 'views')
      end
      
      def default_controller_paths
        [ File.join(RAILS_ROOT, 'app', 'controllers'), File.join(RAILS_ROOT, 'components') ]
      end
  end
188
end