diff options
Diffstat (limited to 'railties/lib')
-rw-r--r-- | railties/lib/rails/application.rb | 104 | ||||
-rw-r--r-- | railties/lib/rails/application/bootstrap.rb | 7 | ||||
-rw-r--r-- | railties/lib/rails/application/configuration.rb | 47 | ||||
-rw-r--r-- | railties/lib/rails/application/finisher.rb | 44 | ||||
-rw-r--r-- | railties/lib/rails/application/routes_reloader.rb | 10 | ||||
-rw-r--r-- | railties/lib/rails/engine.rb | 6 | ||||
-rw-r--r-- | railties/lib/rails/generators/app_base.rb | 2 | ||||
-rw-r--r-- | railties/lib/rails/railtie/configuration.rb | 12 |
8 files changed, 169 insertions, 63 deletions
diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index f5f47acfbc..0b8eac8a8b 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -33,6 +33,25 @@ module Rails # # The Application is also responsible for building the middleware stack. # + # == Booting process + # + # The application is also responsible for setting up and executing the booting + # process. From the moment you require "config/application.rb" in your app, + # the booting process goes like this: + # + # 1) require "config/boot.rb" to setup load paths + # 2) require railties and engines + # 3) Define Rails.application as "class MyApp::Application < Rails::Application" + # 4) Run config.before_configuration callbacks + # 5) Load config/environments/ENV.rb + # 6) Run config.before_initialize callbacks + # 7) Run Railtie#initializer defined by railties, engines and application. + # One by one, each engine sets up its load paths, routes, locales and so on. + # 8) Runs all registered config/initializers/*, executing the engines one first + # 9) Build the middleware stack and run to_prepare callbacks + # 10) Run config.before_eager_load and eager_load if cache classes is true + # 11) Run config.after_initialize callbacks + # class Application < Engine autoload :Bootstrap, 'rails/application/bootstrap' autoload :Configuration, 'rails/application/configuration' @@ -52,12 +71,14 @@ module Rails attr_accessor :assets, :sandbox alias_method :sandbox?, :sandbox + attr_reader :reloaders delegate :default_url_options, :default_url_options=, :to => :routes def initialize super @initialized = false + @reloaders = [] end # This method is called just after an application inherits from Rails::Application, @@ -83,27 +104,83 @@ module Rails require environment if environment end + # Reload application routes regardless if they changed or not. def reload_routes! routes_reloader.reload! end - def routes_reloader + def routes_reloader #:nodoc: @routes_reloader ||= RoutesReloader.new end - def initialize!(group=:default) + # A routes reloader hook that is used to setup to_prepare callbacks. + # A plugin may override this if they desire to provide a more + # exquisite route reloading. + # :api: plugin + def set_routes_reloader_hook + reloader = routes_reloader + hook = lambda { reloader.execute_if_updated } + hook.call + self.reloaders << reloader + ActionDispatch::Reloader.to_prepare(&hook) + end + + # An app dependencies hook that is used to setup to_cleanup callbacks. + # A plugin may override this if they desire to provide a more exquisite app reloading. + # :api: plugin + def set_dependencies_hook + callback = lambda do + ActiveSupport::DescendantsTracker.clear + ActiveSupport::Dependencies.clear + end + + if config.reload_classes_only_on_change + reloader = ActiveSupport::FileUpdateChecker.new(watchable_args, true, &callback) + self.reloaders << reloader + # We need to set a to_prepare callback regardless of the reloader result, i.e. + # models should be reloaded if any of the reloaders (i18n, routes) were updated. + ActionDispatch::Reloader.to_prepare(:prepend => true, &callback) + else + ActionDispatch::Reloader.to_cleanup(&callback) + end + end + + # Returns an array of file paths appended with a hash of directories-extensions + # suitable for ActiveSupport::FileUpdateChecker API. + def watchable_args + files = [] + files.concat config.watchable_files + + dirs = {} + dirs.merge! config.watchable_dirs + ActiveSupport::Dependencies.autoload_paths.each do |path| + dirs[path.to_s] = [:rb] + end + + files << dirs + end + + # Initialize the application passing the given group. By default, the + # group is :default but sprockets precompilation passes group equals + # to assets if initialize_on_precompile is false to avoid booting the + # whole app. + def initialize!(group=:default) #:nodoc: raise "Application has been already initialized." if @initialized run_initializers(group, self) @initialized = true self end + # Load the application and its railties tasks and invoke the registered hooks. + # Check <tt>Rails::Railtie.rake_tasks</tt> for more info. def load_tasks(app=self) initialize_tasks super self end + # Load the application console and invoke the registered hooks. + # Check <tt>Rails::Railtie.console</tt> for more info. def load_console(app=self) initialize_console super @@ -129,7 +206,8 @@ module Rails }) end - def ordered_railties + # Returns the ordered railties for this application considering railties_order. + def ordered_railties #:nodoc: @ordered_railties ||= begin order = config.railties_order.map do |railtie| if railtie == :main_app @@ -151,13 +229,13 @@ module Rails end end - def initializers + def initializers #:nodoc: Bootstrap.initializers_for(self) + super + Finisher.initializers_for(self) end - def config + def config #:nodoc: @config ||= Application::Configuration.new(find_root_with_flag("config.ru", Dir.pwd)) end @@ -165,7 +243,7 @@ module Rails self end - def helpers_paths + def helpers_paths #:nodoc: config.helpers_paths end @@ -173,6 +251,10 @@ module Rails alias :build_middleware_stack :app + def reload_dependencies? + config.reload_classes_only_on_change != true || reloaders.map(&:updated?).any? + end + def default_middleware_stack ActionDispatch::MiddlewareStack.new.tap do |middleware| if rack_cache = config.action_controller.perform_caching && config.action_dispatch.rack_cache @@ -202,7 +284,11 @@ module Rails middleware.use ::Rack::Sendfile, config.action_dispatch.x_sendfile_header end - middleware.use ::ActionDispatch::Reloader unless config.cache_classes + unless config.cache_classes + app = self + middleware.use ::ActionDispatch::Reloader, lambda { app.reload_dependencies? } + end + middleware.use ::ActionDispatch::Callbacks middleware.use ::ActionDispatch::Cookies @@ -222,7 +308,7 @@ module Rails end end - def initialize_tasks + def initialize_tasks #:nodoc: self.class.rake_tasks do require "rails/tasks" task :environment do @@ -232,7 +318,7 @@ module Rails end end - def initialize_console + def initialize_console #:nodoc: require "pp" require "rails/console/app" require "rails/console/helpers" diff --git a/railties/lib/rails/application/bootstrap.rb b/railties/lib/rails/application/bootstrap.rb index 1ae90056d9..e189009cc5 100644 --- a/railties/lib/rails/application/bootstrap.rb +++ b/railties/lib/rails/application/bootstrap.rb @@ -59,13 +59,6 @@ module Rails end end - initializer :set_clear_dependencies_hook, :group => :all do - ActionDispatch::Reloader.to_cleanup do - ActiveSupport::DescendantsTracker.clear - ActiveSupport::Dependencies.clear - end - end - # Sets the dependency loading mechanism. # TODO: Remove files from the $" and always use require. initializer :initialize_dependency_mechanism, :group => :all do diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb index e95b0f5495..39d66ecc31 100644 --- a/railties/lib/rails/application/configuration.rb +++ b/railties/lib/rails/application/configuration.rb @@ -7,11 +7,11 @@ module Rails class Configuration < ::Rails::Engine::Configuration attr_accessor :allow_concurrency, :asset_host, :asset_path, :assets, :cache_classes, :cache_store, :consider_all_requests_local, - :dependency_loading, :filter_parameters, - :force_ssl, :helpers_paths, :logger, :log_tags, :preload_frameworks, - :reload_plugins, :secret_token, :serve_static_assets, - :ssl_options, :static_cache_control, :session_options, - :time_zone, :whiny_nils, :railties_order + :dependency_loading, :filter_parameters, :force_ssl, :helpers_paths, + :initializers_paths, :logger, :log_tags, :preload_frameworks, + :railties_order, :relative_url_root, :reload_plugins, :secret_token, + :serve_static_assets, :ssl_options, :static_cache_control, :session_options, + :time_zone, :reload_classes_only_on_change, :whiny_nils attr_writer :log_level attr_reader :encoding @@ -19,23 +19,26 @@ module Rails def initialize(*) super self.encoding = "utf-8" - @allow_concurrency = false - @consider_all_requests_local = false - @filter_parameters = [] - @helpers_paths = [] - @dependency_loading = true - @serve_static_assets = true - @static_cache_control = nil - @force_ssl = false - @ssl_options = {} - @session_store = :cookie_store - @session_options = {} - @time_zone = "UTC" - @log_level = nil - @middleware = app_middleware - @generators = app_generators - @cache_store = [ :file_store, "#{root}/tmp/cache/" ] - @railties_order = [:all] + @allow_concurrency = false + @consider_all_requests_local = false + @filter_parameters = [] + @helpers_paths = [] + @dependency_loading = true + @serve_static_assets = true + @static_cache_control = nil + @force_ssl = false + @ssl_options = {} + @session_store = :cookie_store + @session_options = {} + @time_zone = "UTC" + @log_level = nil + @middleware = app_middleware + @generators = app_generators + @cache_store = [ :file_store, "#{root}/tmp/cache/" ] + @railties_order = [:all] + @initializers_paths = [] + @relative_url_root = ENV["RAILS_RELATIVE_URL_ROOT"] + @reload_classes_only_on_change = true @assets = ActiveSupport::OrderedOptions.new @assets.enabled = false diff --git a/railties/lib/rails/application/finisher.rb b/railties/lib/rails/application/finisher.rb index fc7d205a6f..e000f6ef3a 100644 --- a/railties/lib/rails/application/finisher.rb +++ b/railties/lib/rails/application/finisher.rb @@ -4,6 +4,10 @@ module Rails include Initializable $rails_rake_task = nil + initializer :load_config_initializers do + config.initializers_paths.each { |init| load(init) } + end + initializer :add_generator_templates do config.generators.templates.unshift(*paths["lib/templates"].existent) end @@ -20,12 +24,6 @@ module Rails end end - initializer :add_to_prepare_blocks do - config.to_prepare_blocks.each do |block| - ActionDispatch::Reloader.to_prepare(&block) - end - end - initializer :add_builtin_route do |app| if Rails.env.development? app.routes.append do @@ -38,14 +36,22 @@ module Rails build_middleware_stack end - initializer :run_prepare_callbacks do - ActionDispatch::Reloader.prepare! - end - initializer :define_main_app_helper do |app| app.routes.define_mounted_helper(:main_app) end + initializer :add_to_prepare_blocks do + config.to_prepare_blocks.each do |block| + ActionDispatch::Reloader.to_prepare(&block) + end + end + + # This needs to happen before eager load so it happens + # in exactly the same point regardless of config.cache_classes + initializer :run_prepare_callbacks do + ActionDispatch::Reloader.prepare! + end + initializer :eager_load! do if config.cache_classes && !$rails_rake_task ActiveSupport.run_load_hooks(:before_eager_load, self) @@ -53,17 +59,21 @@ module Rails end end + # All initialization is done, including eager loading in production initializer :finisher_hook do ActiveSupport.run_load_hooks(:after_initialize, self) end - # Force routes to be loaded just at the end and add it to to_prepare callbacks - # This needs to be after the finisher hook to ensure routes added in the hook - # are still loaded. - initializer :set_routes_reloader do |app| - reloader = lambda { app.routes_reloader.execute_if_updated } - reloader.call - ActionDispatch::Reloader.to_prepare(&reloader) + # Set app reload just after the finisher hook to ensure + # routes added in the hook are still loaded. + initializer :set_routes_reloader_hook do |app| + app.set_routes_reloader_hook + end + + # Set app reload just after the finisher hook to ensure + # paths added in the hook are still loaded. + initializer :set_dependencies_hook, :group => :all do |app| + app.set_dependencies_hook end # Disable dependency loading during request cycle diff --git a/railties/lib/rails/application/routes_reloader.rb b/railties/lib/rails/application/routes_reloader.rb index 1d1f5e1b06..460b84dfd9 100644 --- a/railties/lib/rails/application/routes_reloader.rb +++ b/railties/lib/rails/application/routes_reloader.rb @@ -1,10 +1,14 @@ +require "active_support/core_ext/module/delegation" + module Rails class Application - class RoutesReloader < ::ActiveSupport::FileUpdateChecker + class RoutesReloader attr_reader :route_sets - def initialize - super([]) { reload! } + delegate :paths, :execute_if_updated, :updated?, :to => :@updater + + def initialize(updater=ActiveSupport::FileUpdateChecker) + @updater = updater.new([]) { reload! } @route_sets = [] end diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb index 5c1af99fe2..86efc7332c 100644 --- a/railties/lib/rails/engine.rb +++ b/railties/lib/rails/engine.rb @@ -583,10 +583,8 @@ module Rails end end - initializer :load_config_initializers do - config.paths["config/initializers"].existent.sort.each do |initializer| - load(initializer) - end + initializer :append_config_initializers do |app| + app.config.initializers_paths.concat config.paths["config/initializers"].existent.sort end initializer :engines_blank_point do diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb index e3d22e81fb..0bd39cb2cd 100644 --- a/railties/lib/rails/generators/app_base.rb +++ b/railties/lib/rails/generators/app_base.rb @@ -194,7 +194,7 @@ module Rails def assets_gemfile_entry return if options[:skip_sprockets] - <<-GEMFILE.strip_heredoc + <<-GEMFILE.strip_heredoc.gsub(/^[ \t]*$/, '') # Gems used only for assets and not required # in production environments by default. group :assets do diff --git a/railties/lib/rails/railtie/configuration.rb b/railties/lib/rails/railtie/configuration.rb index f888684117..cf9e4ad500 100644 --- a/railties/lib/rails/railtie/configuration.rb +++ b/railties/lib/rails/railtie/configuration.rb @@ -7,6 +7,18 @@ module Rails @@options ||= {} end + # Add files that should be watched for change. + def watchable_files + @@watchable_files ||= [] + end + + # Add directories that should be watched for change. + # The key of the hashes should be directories and the values should + # be an array of extensions to match in each directory. + def watchable_dirs + @@watchable_dirs ||= {} + end + # This allows you to modify the application's middlewares from Engines. # # All operations you run on the app_middleware will be replayed on the |