aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionpack/lib/action_dispatch/middleware/reloader.rb52
-rw-r--r--actionpack/test/dispatch/reloader_test.rb22
-rw-r--r--activerecord/lib/active_record/railtie.rb5
-rw-r--r--activesupport/lib/active_support/file_update_checker.rb79
-rw-r--r--activesupport/lib/active_support/i18n_railtie.rb3
-rw-r--r--activesupport/test/file_update_checker_test.rb66
-rw-r--r--railties/CHANGELOG.md7
-rw-r--r--railties/guides/source/configuring.textile2
-rw-r--r--railties/lib/rails/application.rb40
-rw-r--r--railties/lib/rails/application/configuration.rb49
-rw-r--r--railties/lib/rails/application/finisher.rb14
-rw-r--r--railties/lib/rails/application/routes_reloader.rb12
-rw-r--r--railties/lib/rails/engine.rb2
-rw-r--r--railties/lib/rails/generators/app_base.rb2
-rw-r--r--railties/lib/rails/railtie/configuration.rb12
-rw-r--r--railties/test/application/console_test.rb3
-rw-r--r--railties/test/application/loading_test.rb1
-rw-r--r--railties/test/generators/app_generator_test.rb10
18 files changed, 288 insertions, 93 deletions
diff --git a/actionpack/lib/action_dispatch/middleware/reloader.rb b/actionpack/lib/action_dispatch/middleware/reloader.rb
index 29289a76b4..4f48f1c974 100644
--- a/actionpack/lib/action_dispatch/middleware/reloader.rb
+++ b/actionpack/lib/action_dispatch/middleware/reloader.rb
@@ -43,34 +43,58 @@ module ActionDispatch
# Execute all prepare callbacks.
def self.prepare!
- new(nil).run_callbacks :prepare
+ new(nil).prepare!
end
# Execute all cleanup callbacks.
def self.cleanup!
- new(nil).run_callbacks :cleanup
+ new(nil).cleanup!
end
- def initialize(app)
+ def initialize(app, condition=nil)
@app = app
- end
-
- module CleanupOnClose
- def close
- super if defined?(super)
- ensure
- ActionDispatch::Reloader.cleanup!
- end
+ @condition = condition || lambda { true }
+ @validated = true
end
def call(env)
- run_callbacks :prepare
+ @validated = @condition.call
+ prepare!
response = @app.call(env)
- response[2].extend(CleanupOnClose)
+ response[2].extend(module_hook)
response
rescue Exception
- run_callbacks :cleanup
+ cleanup!
raise
end
+
+ def prepare! #:nodoc:
+ run_callbacks :prepare if validated?
+ end
+
+ def cleanup! #:nodoc:
+ run_callbacks :cleanup if validated?
+ ensure
+ @validated = true
+ end
+
+ private
+
+ def validated? #:nodoc:
+ @validated
+ end
+
+ def module_hook #:nodoc:
+ middleware = self
+ Module.new do
+ define_method :close do
+ begin
+ super() if defined?(super)
+ ensure
+ middleware.cleanup!
+ end
+ end
+ end
+ end
end
end
diff --git a/actionpack/test/dispatch/reloader_test.rb b/actionpack/test/dispatch/reloader_test.rb
index eaabc1feb3..3411bd14ea 100644
--- a/actionpack/test/dispatch/reloader_test.rb
+++ b/actionpack/test/dispatch/reloader_test.rb
@@ -43,6 +43,19 @@ class ReloaderTest < Test::Unit::TestCase
assert_respond_to body, :close
end
+ def test_condition_specifies_when_to_reload
+ i, j = 0, 0, 0, 0
+ Reloader.to_prepare { |*args| i += 1 }
+ Reloader.to_cleanup { |*args| j += 1 }
+ app = Reloader.new(lambda { |env| [200, {}, []] }, lambda { i < 3 })
+ 5.times do
+ resp = app.call({})
+ resp[2].close
+ end
+ assert_equal 3, i
+ assert_equal 3, j
+ end
+
def test_returned_body_object_behaves_like_underlying_object
body = call_and_return_body do
b = MyBody.new
@@ -116,6 +129,15 @@ class ReloaderTest < Test::Unit::TestCase
assert cleaned
end
+ def test_prepend_prepare_callback
+ i = 10
+ Reloader.to_prepare { i += 1 }
+ Reloader.to_prepare(:prepend => true) { i = 0 }
+
+ Reloader.prepare!
+ assert_equal 1, i
+ end
+
def test_cleanup_callbacks_are_called_on_exceptions
cleaned = false
Reloader.to_cleanup { cleaned = true }
diff --git a/activerecord/lib/active_record/railtie.rb b/activerecord/lib/active_record/railtie.rb
index c2e31579a4..71772529d2 100644
--- a/activerecord/lib/active_record/railtie.rb
+++ b/activerecord/lib/active_record/railtie.rb
@@ -94,6 +94,11 @@ module ActiveRecord
end
end
+ initializer "active_record.add_watchable_files" do |app|
+ files = ["#{app.root}/db/schema.rb", "#{app.root}/db/structure.sql"]
+ config.watchable_files.concat files.select { |f| File.exist?(f) }
+ end
+
config.after_initialize do
ActiveSupport.on_load(:active_record) do
instantiate_observers
diff --git a/activesupport/lib/active_support/file_update_checker.rb b/activesupport/lib/active_support/file_update_checker.rb
index 9d617b39d4..4137bbf6a0 100644
--- a/activesupport/lib/active_support/file_update_checker.rb
+++ b/activesupport/lib/active_support/file_update_checker.rb
@@ -1,3 +1,6 @@
+require "active_support/core_ext/array/wrap"
+require "active_support/core_ext/array/extract_options"
+
module ActiveSupport
# This class is responsible to track files and invoke the given block
# whenever one of these files are changed. For example, this class
@@ -15,24 +18,86 @@ module ActiveSupport
class FileUpdateChecker
attr_reader :paths, :last_update_at
+ # It accepts two parameters on initialization. The first is
+ # the *paths* and the second is *calculate*, a boolean.
+ #
+ # paths must be an array of file paths but can contain a hash as
+ # last argument. The hash must have directories as keys and the
+ # value is an array of extensions to be watched under that directory.
+ #
+ # If *calculate* is true, the latest updated at will calculated
+ # on initialization, therefore, the first call to execute_if_updated
+ # will only evaluate the block if something really changed.
+ #
+ # This method must also receive a block that will be the block called
+ # once a file changes.
+ #
+ # This particular implementation checks for added files and updated files,
+ # but not removed files. Directories lookup are compiled to a glob for
+ # performance.
def initialize(paths, calculate=false, &block)
@paths = paths
+ @glob = compile_glob(@paths.extract_options!)
@block = block
+ @updated_at = nil
@last_update_at = calculate ? updated_at : nil
end
- def updated_at
- # TODO: Use Enumerable check once we get rid of 1.8.7
- all = paths.is_a?(Array) ? paths : Dir[paths]
- all.map { |path| File.mtime(path) }.max
+ # Check if any of the entries were updated. If so, the updated_at
+ # value is cached until flush! is called.
+ def updated?
+ current_updated_at = updated_at
+ if @last_update_at != current_updated_at
+ @updated_at = updated_at
+ true
+ else
+ false
+ end
+ end
+
+ # Flush the cache so updated? is calculated again
+ def flush!
+ @updated_at = nil
end
+ # Execute the block given if updated. This call
+ # always flush the cache.
def execute_if_updated
- current_update_at = self.updated_at
- if @last_update_at != current_update_at
- @last_update_at = current_update_at
+ if updated?
+ @last_update_at = updated_at
@block.call
+ true
+ else
+ false
end
+ ensure
+ flush!
+ end
+
+ private
+
+ def updated_at #:nodoc:
+ @updated_at || begin
+ all = []
+ all.concat @paths
+ all.concat Dir[@glob] if @glob
+ all.map { |path| File.mtime(path) }.max
+ end
+ end
+
+ def compile_glob(hash) #:nodoc:
+ return if hash.empty?
+ globs = []
+ hash.each do |key, value|
+ globs << "#{key}/**/*#{compile_ext(value)}"
+ end
+ "{#{globs.join(",")}}"
+ end
+
+ def compile_ext(array) #:nodoc:
+ array = Array.wrap(array)
+ return if array.empty?
+ ".{#{array.join(",")}}"
end
end
end
diff --git a/activesupport/lib/active_support/i18n_railtie.rb b/activesupport/lib/active_support/i18n_railtie.rb
index 4c59fe9ac9..a989ff8f57 100644
--- a/activesupport/lib/active_support/i18n_railtie.rb
+++ b/activesupport/lib/active_support/i18n_railtie.rb
@@ -17,7 +17,8 @@ module I18n
# point, no path was added to the reloader, I18n.reload! is not triggered
# on to_prepare callbacks. This will only happen on the config.after_initialize
# callback below.
- initializer "i18n.callbacks" do
+ initializer "i18n.callbacks" do |app|
+ app.reloaders << I18n::Railtie.reloader
ActionDispatch::Reloader.to_prepare do
I18n::Railtie.reloader.execute_if_updated
end
diff --git a/activesupport/test/file_update_checker_test.rb b/activesupport/test/file_update_checker_test.rb
index 425931f49a..52c1f3260d 100644
--- a/activesupport/test/file_update_checker_test.rb
+++ b/activesupport/test/file_update_checker_test.rb
@@ -4,21 +4,19 @@ require 'fileutils'
MTIME_FIXTURES_PATH = File.expand_path("../fixtures", __FILE__)
-module FileUpdateCheckerSuite
+class FileUpdateCheckerWithEnumerableTest < Test::Unit::TestCase
FILES = %w(1.txt 2.txt 3.txt)
def setup
+ FileUtils.mkdir_p("tmp_watcher")
FileUtils.touch(FILES)
end
def teardown
+ FileUtils.rm_rf("tmp_watcher")
FileUtils.rm(FILES)
end
- def args
- raise NotImplementedError
- end
-
def test_should_not_execute_the_block_if_no_paths_are_given
i = 0
checker = ActiveSupport::FileUpdateChecker.new([]){ i += 1 }
@@ -28,42 +26,64 @@ module FileUpdateCheckerSuite
def test_should_invoke_the_block_on_first_call_if_it_does_not_calculate_last_updated_at_on_load
i = 0
- checker = ActiveSupport::FileUpdateChecker.new(args){ i += 1 }
+ checker = ActiveSupport::FileUpdateChecker.new(FILES){ i += 1 }
checker.execute_if_updated
assert_equal 1, i
end
def test_should_not_invoke_the_block_on_first_call_if_it_calculates_last_updated_at_on_load
i = 0
- checker = ActiveSupport::FileUpdateChecker.new(args, true){ i += 1 }
+ checker = ActiveSupport::FileUpdateChecker.new(FILES, true){ i += 1 }
checker.execute_if_updated
assert_equal 0, i
end
def test_should_not_invoke_the_block_if_no_file_has_changed
i = 0
- checker = ActiveSupport::FileUpdateChecker.new(args){ i += 1 }
- 5.times { checker.execute_if_updated }
- assert_equal 1, i
+ checker = ActiveSupport::FileUpdateChecker.new(FILES, true){ i += 1 }
+ 5.times { assert !checker.execute_if_updated }
+ assert_equal 0, i
end
def test_should_invoke_the_block_if_a_file_has_changed
i = 0
- checker = ActiveSupport::FileUpdateChecker.new(args){ i += 1 }
- checker.execute_if_updated
+ checker = ActiveSupport::FileUpdateChecker.new(FILES, true){ i += 1 }
sleep(1)
FileUtils.touch(FILES)
- checker.execute_if_updated
- assert_equal 2, i
+ assert checker.execute_if_updated
+ assert_equal 1, i
end
-end
-class FileUpdateCheckerWithEnumerableTest < Test::Unit::TestCase
- include FileUpdateCheckerSuite
- def args; FILES; end
-end
+ def test_should_cache_updated_result_until_flushed
+ i = 0
+ checker = ActiveSupport::FileUpdateChecker.new(FILES, true){ i += 1 }
+ assert !checker.updated?
+
+ sleep(1)
+ FileUtils.touch(FILES)
+
+ assert checker.updated?
+ assert checker.execute_if_updated
+ assert !checker.updated?
+ end
-class FileUpdateCheckerWithStringTest < Test::Unit::TestCase
- include FileUpdateCheckerSuite
- def args; "{1,2,3}.txt"; end
-end
+ def test_should_invoke_the_block_if_a_watched_dir_changed_its_glob
+ i = 0
+ checker = ActiveSupport::FileUpdateChecker.new([{"tmp_watcher" => [:txt]}], true){ i += 1 }
+ FileUtils.cd "tmp_watcher" do
+ FileUtils.touch(FILES)
+ end
+ assert checker.execute_if_updated
+ assert_equal 1, i
+ end
+
+ def test_should_not_invoke_the_block_if_a_watched_dir_changed_its_glob
+ i = 0
+ checker = ActiveSupport::FileUpdateChecker.new([{"tmp_watcher" => :rb}], true){ i += 1 }
+ FileUtils.cd "tmp_watcher" do
+ FileUtils.touch(FILES)
+ end
+ assert !checker.execute_if_updated
+ assert_equal 0, i
+ end
+end \ No newline at end of file
diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md
index 2841996b56..a88f443517 100644
--- a/railties/CHANGELOG.md
+++ b/railties/CHANGELOG.md
@@ -1,9 +1,8 @@
## Rails 3.2.0 (unreleased) ##
-* New applications get a flag
- `config.active_record.auto_explain_threshold_in_seconds` in the environments
- configuration files. With a value of 0.5 in development.rb, and commented
- out in production.rb. No mention in test.rb. *fxn*
+* Speed up development by only reloading classes if dependencies files changed. This can be turned off by setting `config.reload_classes_only_on_change` to false. *José Valim*
+
+* New applications get a flag `config.active_record.auto_explain_threshold_in_seconds` in the environments configuration files. With a value of 0.5 in development.rb, and commented out in production.rb. No mention in test.rb. *fxn*
* Add DebugExceptions middleware which contains features extracted from ShowExceptions middleware *José Valim*
diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile
index 8e65dbccbb..8cf88cf71f 100644
--- a/railties/guides/source/configuring.textile
+++ b/railties/guides/source/configuring.textile
@@ -98,6 +98,8 @@ NOTE. The +config.asset_path+ configuration is ignored if the asset pipeline is
* +config.preload_frameworks+ enables or disables preloading all frameworks at startup. Enabled by +config.threadsafe!+. Defaults to +nil+, so is disabled.
+* +config.reload_classes_only_on_change+ enables or disables reloading of classes only when tracked files change. By default tracks everything on autoload paths and is set to true.
+
* +config.reload_plugins+ enables or disables plugin reloading. Defaults to false.
* +config.secret_token+ used for specifying a key which allows sessions for the application to be verified against a known secure key to prevent tampering. Applications get +config.secret_token+ initialized to a random key in +config/initializers/secret_token.rb+.
diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb
index acbfd7078b..0b8eac8a8b 100644
--- a/railties/lib/rails/application.rb
+++ b/railties/lib/rails/application.rb
@@ -71,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,
@@ -119,6 +121,7 @@ module Rails
reloader = routes_reloader
hook = lambda { reloader.execute_if_updated }
hook.call
+ self.reloaders << reloader
ActionDispatch::Reloader.to_prepare(&hook)
end
@@ -126,10 +129,35 @@ module Rails
# A plugin may override this if they desire to provide a more exquisite app reloading.
# :api: plugin
def set_dependencies_hook
- ActionDispatch::Reloader.to_cleanup do
+ 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
@@ -223,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
@@ -252,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
diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb
index 4b2afe3a28..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,
- :relative_url_root, :reload_plugins, :secret_token, :serve_static_assets,
- :ssl_options, :static_cache_control, :session_options,
- :time_zone, :whiny_nils, :railties_order, :all_initializers
+ :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,25 +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]
- @all_initializers = []
- @relative_url_root = ENV["RAILS_RELATIVE_URL_ROOT"]
+ @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 17e7aa0f28..e000f6ef3a 100644
--- a/railties/lib/rails/application/finisher.rb
+++ b/railties/lib/rails/application/finisher.rb
@@ -5,7 +5,7 @@ module Rails
$rails_rake_task = nil
initializer :load_config_initializers do
- config.all_initializers.each { |init| load(init) }
+ config.initializers_paths.each { |init| load(init) }
end
initializer :add_generator_templates do
@@ -65,17 +65,17 @@ module Rails
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
-
- # 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
initializer :disable_dependency_loading do
if config.cache_classes && !config.dependency_loading
diff --git a/railties/lib/rails/application/routes_reloader.rb b/railties/lib/rails/application/routes_reloader.rb
index c1f435a3ee..460b84dfd9 100644
--- a/railties/lib/rails/application/routes_reloader.rb
+++ b/railties/lib/rails/application/routes_reloader.rb
@@ -1,21 +1,17 @@
+require "active_support/core_ext/module/delegation"
+
module Rails
class Application
class RoutesReloader
attr_reader :route_sets
+ delegate :paths, :execute_if_updated, :updated?, :to => :@updater
+
def initialize(updater=ActiveSupport::FileUpdateChecker)
@updater = updater.new([]) { reload! }
@route_sets = []
end
- def paths
- @updater.paths
- end
-
- def execute_if_updated
- @updater.execute_if_updated
- end
-
def reload!
clear!
load_paths
diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb
index 8ebe1f48a5..86efc7332c 100644
--- a/railties/lib/rails/engine.rb
+++ b/railties/lib/rails/engine.rb
@@ -584,7 +584,7 @@ module Rails
end
initializer :append_config_initializers do |app|
- app.config.all_initializers.concat config.paths["config/initializers"].existent.sort
+ 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
diff --git a/railties/test/application/console_test.rb b/railties/test/application/console_test.rb
index 2073c780bf..6f9d8d57b1 100644
--- a/railties/test/application/console_test.rb
+++ b/railties/test/application/console_test.rb
@@ -61,7 +61,8 @@ class ConsoleTest < Test::Unit::TestCase
load_environment
assert User.new.respond_to?(:name)
- assert !User.new.respond_to?(:age)
+
+ sleep(1)
app_file "app/models/user.rb", <<-MODEL
class User
diff --git a/railties/test/application/loading_test.rb b/railties/test/application/loading_test.rb
index 47c6fd5c6e..c4908915dc 100644
--- a/railties/test/application/loading_test.rb
+++ b/railties/test/application/loading_test.rb
@@ -66,6 +66,7 @@ class LoadingTest < Test::Unit::TestCase
def test_descendants_are_cleaned_on_each_request_without_cache_classes
add_to_config <<-RUBY
config.cache_classes = false
+ config.reload_classes_only_on_change = false
RUBY
app_file "app/models/post.rb", <<-MODEL
diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb
index ef9f2b22a7..30fbe74e83 100644
--- a/railties/test/generators/app_generator_test.rb
+++ b/railties/test/generators/app_generator_test.rb
@@ -124,6 +124,16 @@ class AppGeneratorTest < Rails::Generators::TestCase
assert_file "hats/config/environment.rb", /Hats::Application\.initialize!/
end
+ def test_gemfile_has_no_whitespace_errors
+ run_generator
+ absolute = File.expand_path("Gemfile", destination_root)
+ File.open(absolute, 'r') do |f|
+ f.each_line do |line|
+ assert_no_match /^[ \t]+$/, line
+ end
+ end
+ end
+
def test_config_database_is_added_by_default
run_generator
assert_file "config/database.yml", /sqlite3/