From b33700f5580b4cd85379a1dc60fa341ac4d8deb2 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Tue, 28 Aug 2012 20:27:59 +0200 Subject: detect circular constant autoloading Nowadays circular autoloads do not work, but the user gets a NameError that says some constant is undefined. That's puzzling, because he is normally trying to autoload a constant he knows can be autoloaded. With this check we can give a better error message. --- activesupport/lib/active_support/dependencies.rb | 15 +++++++++++---- activesupport/test/autoloading_fixtures/circular1.rb | 6 ++++++ activesupport/test/autoloading_fixtures/circular2.rb | 4 ++++ activesupport/test/dependencies_test.rb | 6 ++++++ 4 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 activesupport/test/autoloading_fixtures/circular1.rb create mode 100644 activesupport/test/autoloading_fixtures/circular2.rb (limited to 'activesupport') diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb index 26545d8553..d2afea2545 100644 --- a/activesupport/lib/active_support/dependencies.rb +++ b/activesupport/lib/active_support/dependencies.rb @@ -479,10 +479,17 @@ module ActiveSupport #:nodoc: file_path = search_for_file(path_suffix) - if file_path && ! loaded.include?(File.expand_path(file_path).sub(/\.rb\z/, '')) # We found a matching file to load - require_or_load file_path - raise LoadError, "Expected #{file_path} to define #{qualified_name}" unless from_mod.const_defined?(const_name, false) - return from_mod.const_get(const_name) + if file_path + expanded = File.expand_path(file_path) + expanded.sub!(/\.rb/, '') + + if loaded.include?(expanded) + raise "Circular dependency detected while autoloading constant #{qualified_name}" + else + require_or_load(expanded) + raise LoadError, "Expected #{file_path} to define #{qualified_name}" unless from_mod.const_defined?(const_name, false) + return from_mod.const_get(const_name) + end elsif mod = autoload_module!(from_mod, const_name, qualified_name, path_suffix) return mod elsif (parent = from_mod.parent) && parent != from_mod && diff --git a/activesupport/test/autoloading_fixtures/circular1.rb b/activesupport/test/autoloading_fixtures/circular1.rb new file mode 100644 index 0000000000..a45761f066 --- /dev/null +++ b/activesupport/test/autoloading_fixtures/circular1.rb @@ -0,0 +1,6 @@ +silence_warnings do + Circular2 +end + +class Circular1 +end diff --git a/activesupport/test/autoloading_fixtures/circular2.rb b/activesupport/test/autoloading_fixtures/circular2.rb new file mode 100644 index 0000000000..c847fa5001 --- /dev/null +++ b/activesupport/test/autoloading_fixtures/circular2.rb @@ -0,0 +1,4 @@ +Circular1 + +class Circular2 +end diff --git a/activesupport/test/dependencies_test.rb b/activesupport/test/dependencies_test.rb index f1da6378a7..e5bc806397 100644 --- a/activesupport/test/dependencies_test.rb +++ b/activesupport/test/dependencies_test.rb @@ -145,6 +145,12 @@ class DependenciesTest < ActiveSupport::TestCase end end + def test_circular_autoloading_detection + with_autoloading_fixtures do + assert_raise(RuntimeError, "Circular dependency detected while autoloading constant Circular1") { Circular1 } + end + end + def test_module_loading with_autoloading_fixtures do assert_kind_of Module, A -- cgit v1.2.3