fixes circularity check in dependencies

The check for circular loading should depend on a stack of files being
loaded at the moment, rather than the collection of loaded files.

This showed up indirectly in #16468, where a misspelled helper would
incorrectly result in a circularity error message.

References #16468
This commit is contained in:
Xavier Noria 2014-10-25 13:50:42 +02:00
parent c4767e13d4
commit ae07806858
4 changed files with 37 additions and 1 deletions

View File

@ -30,6 +30,10 @@ module ActiveSupport #:nodoc:
mattr_accessor :loaded
self.loaded = Set.new
# Stack of files being loaded.
mattr_accessor :loading
self.loading = []
# Should we load files or require them?
mattr_accessor :mechanism
self.mechanism = ENV['NO_RELOAD'] ? :require : :load
@ -317,6 +321,7 @@ module ActiveSupport #:nodoc:
def clear
log_call
loaded.clear
loading.clear
remove_unloadable_constants!
end
@ -329,6 +334,7 @@ module ActiveSupport #:nodoc:
# Record that we've seen this file *before* loading it to avoid an
# infinite loop with mutual dependencies.
loaded << expanded
loading << expanded
begin
if load?
@ -351,6 +357,8 @@ module ActiveSupport #:nodoc:
rescue Exception
loaded.delete expanded
raise
ensure
loading.pop
end
# Record history *after* loading so first load gets warnings.
@ -475,7 +483,7 @@ module ActiveSupport #:nodoc:
expanded = File.expand_path(file_path)
expanded.sub!(/\.rb\z/, '')
if loaded.include?(expanded)
if loading.include?(expanded)
raise "Circular dependency detected while autoloading constant #{qualified_name}"
else
require_or_load(expanded, qualified_name)

View File

@ -0,0 +1,2 @@
TypO = 1

View File

@ -157,6 +157,31 @@ class DependenciesTest < ActiveSupport::TestCase
end
end
def test_ensures_the_expected_constant_is_defined
with_autoloading_fixtures do
e = assert_raise(LoadError) { Typo }
assert_match %r{Unable to autoload constant Typo, expected .*activesupport/test/autoloading_fixtures/typo.rb to define it}, e.message
end
end
def test_require_dependency_does_not_assume_any_particular_constant_is_defined
with_autoloading_fixtures do
require_dependency 'typo'
assert_equal 1, TypO
end
end
# Regression, see https://github.com/rails/rails/issues/16468.
def test_require_dependency_interaction_with_autoloading
with_autoloading_fixtures do
require_dependency 'typo'
assert_equal 1, TypO
e = assert_raise(LoadError) { Typo }
assert_match %r{Unable to autoload constant Typo, expected .*activesupport/test/autoloading_fixtures/typo.rb to define it}, e.message
end
end
def test_module_loading
with_autoloading_fixtures do
assert_kind_of Module, A

View File

@ -13,6 +13,7 @@ module DependenciesTestHelpers
ActiveSupport::Dependencies.autoload_paths = prior_autoload_paths
ActiveSupport::Dependencies.mechanism = old_mechanism
ActiveSupport::Dependencies.explicitly_unloadable_constants = []
ActiveSupport::Dependencies.clear
end
def with_autoloading_fixtures(&block)