aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport
diff options
context:
space:
mode:
authorRafael França <rafaelmfranca@gmail.com>2018-01-26 13:45:08 -0500
committerGitHub <noreply@github.com>2018-01-26 13:45:08 -0500
commit2f9549d4f46ca1f9cc437d4f89bd8df405e28dbd (patch)
treef03146dadfc7ecd0a15dd2216f0f4a9dcbeffa00 /activesupport
parentce6461992f6521261b9ff5ae43d47814727de39e (diff)
parentd92fb27885ddcb0a92ac67f69bf0eb8c912f4dc7 (diff)
downloadrails-2f9549d4f46ca1f9cc437d4f89bd8df405e28dbd.tar.gz
rails-2f9549d4f46ca1f9cc437d4f89bd8df405e28dbd.tar.bz2
rails-2f9549d4f46ca1f9cc437d4f89bd8df405e28dbd.zip
Merge pull request #31803 from rmosolgo/rm-dependencies
Fix infinite loop when unloading autoloaded modules
Diffstat (limited to 'activesupport')
-rw-r--r--activesupport/lib/active_support/dependencies.rb1
-rw-r--r--activesupport/test/dependencies_test.rb55
2 files changed, 56 insertions, 0 deletions
diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb
index abc648e0c6..0f59558bb5 100644
--- a/activesupport/lib/active_support/dependencies.rb
+++ b/activesupport/lib/active_support/dependencies.rb
@@ -447,6 +447,7 @@ module ActiveSupport #:nodoc:
mod = Module.new
into.const_set const_name, mod
autoloaded_constants << qualified_name unless autoload_once_paths.include?(base_path)
+ autoloaded_constants.uniq!
mod
end
diff --git a/activesupport/test/dependencies_test.rb b/activesupport/test/dependencies_test.rb
index 9dcd1c7200..c0c4c4cac5 100644
--- a/activesupport/test/dependencies_test.rb
+++ b/activesupport/test/dependencies_test.rb
@@ -185,6 +185,61 @@ class DependenciesTest < ActiveSupport::TestCase
end
end
+ # Regression see https://github.com/rails/rails/issues/31694
+ def test_included_constant_that_changes_to_have_exception_then_back_does_not_loop_forever
+ # This constant references a nested constant whose namespace will be auto-generated
+ parent_constant = <<-RUBY
+ class ConstantReloadError
+ AnotherConstant::ReloadError
+ end
+ RUBY
+
+ # This constant's namespace will be auto-generated,
+ # also, we'll edit it to contain an error at load-time
+ child_constant = <<-RUBY
+ class AnotherConstant::ReloadError
+ # no_such_method_as_this
+ end
+ RUBY
+
+ # Create a version which contains an error during loading
+ child_constant_with_error = child_constant.sub("# no_such_method_as_this", "no_such_method_as_this")
+
+ fixtures_path = File.join(__dir__, "autoloading_fixtures")
+ Dir.mktmpdir(nil, fixtures_path) do |tmpdir|
+ # Set up the file structure where constants will be loaded from
+ child_constant_path = "#{tmpdir}/another_constant/reload_error.rb"
+ File.write("#{tmpdir}/constant_reload_error.rb", parent_constant)
+ Dir.mkdir("#{tmpdir}/another_constant")
+ File.write(child_constant_path, child_constant_with_error)
+
+ tmpdir_name = tmpdir.split("/").last
+ with_loading("autoloading_fixtures/#{tmpdir_name}") do
+ # Load the file, with the error:
+ assert_raises(NameError) {
+ ConstantReloadError
+ }
+
+ Timeout.timeout(0.1) do
+ # Remove the constant, as if Rails development middleware is reloading changed files:
+ ActiveSupport::Dependencies.remove_unloadable_constants!
+ refute defined?(AnotherConstant::ReloadError)
+ end
+
+ # Change the file, so that it is **correct** this time:
+ File.write(child_constant_path, child_constant)
+
+ # Again: Remove the constant, as if Rails development middleware is reloading changed files:
+ ActiveSupport::Dependencies.remove_unloadable_constants!
+ refute defined?(AnotherConstant::ReloadError)
+
+ # Now, reload the _fixed_ constant:
+ assert ConstantReloadError
+ assert AnotherConstant::ReloadError
+ end
+ end
+ end
+
def test_module_loading
with_autoloading_fixtures do
assert_kind_of Module, A