diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb index 828015d2f3c08..9a2c933ab5c08 100644 --- a/activesupport/lib/active_support/dependencies.rb +++ b/activesupport/lib/active_support/dependencies.rb @@ -229,10 +229,10 @@ def load_missing_constant(from_mod, const_name) from_mod = Object end end - + # If we have an anonymous module, all we can do is attempt to load from Object. - from_mod = Object if from_mod.name.empty? - + from_mod = Object if from_mod.name.blank? + unless qualified_const_defined?(from_mod.name) && from_mod.name.constantize.object_id == from_mod.object_id raise ArgumentError, "A copy of #{from_mod} has been removed from the module tree but is still active!" end @@ -392,11 +392,9 @@ def self.root(*args) end end -protected - # Convert the provided const desc to a qualified constant name (as a string). # A module, class, symbol, or string may be provided. - def to_constant_name(desc) + def to_constant_name(desc) #:nodoc: name = case desc when String then desc.starts_with?('::') ? desc[2..-1] : desc when Symbol then desc.to_s @@ -406,10 +404,10 @@ def to_constant_name(desc) else raise TypeError, "Not a valid constant descriptor: #{desc.inspect}" end end - - def remove_constant(const) + + def remove_constant(const) #:nodoc: return false unless qualified_const_defined? const - + const = $1 if /\A::(.*)\Z/ =~ const.to_s names = const.to_s.split('::') if names.size == 1 # It's under Object @@ -417,12 +415,13 @@ def remove_constant(const) else parent = (names[0..-2] * '::').constantize end - + log "removing constant #{const}" parent.instance_eval { remove_const names.last } return true end - + +protected def log_call(*args) arg_str = args.collect(&:inspect) * ', ' /in `([a-z_\?\!]+)'/ =~ caller(1).first diff --git a/activesupport/test/dependencies_test.rb b/activesupport/test/dependencies_test.rb index ad3472bddbad7..76f8453c3538a 100644 --- a/activesupport/test/dependencies_test.rb +++ b/activesupport/test/dependencies_test.rb @@ -146,42 +146,42 @@ def test_non_existing_const_raises_name_error def test_directories_manifest_as_modules_unless_const_defined with_loading 'autoloading_fixtures' do assert_kind_of Module, ModuleFolder - Object.send :remove_const, :ModuleFolder + Object.send! :remove_const, :ModuleFolder end end def test_module_with_nested_class with_loading 'autoloading_fixtures' do assert_kind_of Class, ModuleFolder::NestedClass - Object.send :remove_const, :ModuleFolder + Object.send! :remove_const, :ModuleFolder end end def test_module_with_nested_inline_class with_loading 'autoloading_fixtures' do assert_kind_of Class, ModuleFolder::InlineClass - Object.send :remove_const, :ModuleFolder + Object.send! :remove_const, :ModuleFolder end end def test_directories_may_manifest_as_nested_classes with_loading 'autoloading_fixtures' do assert_kind_of Class, ClassFolder - Object.send :remove_const, :ClassFolder + Object.send! :remove_const, :ClassFolder end end def test_class_with_nested_class with_loading 'autoloading_fixtures' do assert_kind_of Class, ClassFolder::NestedClass - Object.send :remove_const, :ClassFolder + Object.send! :remove_const, :ClassFolder end end def test_class_with_nested_inline_class with_loading 'autoloading_fixtures' do assert_kind_of Class, ClassFolder::InlineClass - Object.send :remove_const, :ClassFolder + Object.send! :remove_const, :ClassFolder end end @@ -190,7 +190,7 @@ def test_class_with_nested_inline_subclass_of_parent assert_kind_of Class, ClassFolder::ClassFolderSubclass assert_kind_of Class, ClassFolder assert_equal 'indeed', ClassFolder::ClassFolderSubclass::ConstantInClassFolder - Object.send :remove_const, :ClassFolder + Object.send! :remove_const, :ClassFolder end end @@ -199,7 +199,7 @@ def test_nested_class_can_access_sibling sibling = ModuleFolder::NestedClass.class_eval "NestedSibling" assert defined?(ModuleFolder::NestedSibling) assert_equal ModuleFolder::NestedSibling, sibling - Object.send :remove_const, :ModuleFolder + Object.send! :remove_const, :ModuleFolder end end @@ -208,7 +208,7 @@ def failing_test_access_thru_and_upwards_fails assert ! defined?(ModuleFolder) assert_raises(NameError) { ModuleFolder::Object } assert_raises(NameError) { ModuleFolder::NestedClass::Object } - Object.send :remove_const, :ModuleFolder + Object.send! :remove_const, :ModuleFolder end end @@ -316,7 +316,7 @@ def test_autoloaded? def nil_name.name() nil end assert !Dependencies.autoloaded?(nil_name) - Object.send :remove_const, :ModuleFolder + Object.class_eval { remove_const :ModuleFolder } end end @@ -440,7 +440,7 @@ def test_load_once_paths_do_not_add_to_autoloaded_constants assert ! Dependencies.autoloaded?(ModuleFolder::NestedClass) end ensure - Object.send(:remove_const, :ModuleFolder) if defined?(ModuleFolder) + Object.class_eval { remove_const :ModuleFolder } Dependencies.load_once_paths = [] end @@ -475,7 +475,7 @@ def test_preexisting_constants_are_not_marked_as_autoloaded end ensure - Object.send :remove_const, :E if Object.const_defined?(:E) + Object.class_eval { remove_const :E } end def test_unloadable @@ -513,31 +513,30 @@ def test_new_contants_in_without_constants end def test_new_constants_in_with_a_single_constant - assert_equal(["Hello"], (Dependencies.new_constants_in(Object) do - Object.const_set :Hello, 10 - end)) + assert_equal ["Hello"], Dependencies.new_constants_in(Object) { + Object.const_set :Hello, 10 + }.map(&:to_s) assert Dependencies.constant_watch_stack.empty? ensure - Object.send :remove_const, :Hello rescue nil + Object.class_eval { remove_const :Hello } end def test_new_constants_in_with_nesting outer = Dependencies.new_constants_in(Object) do Object.const_set :OuterBefore, 10 - inner = Dependencies.new_constants_in(Object) do - Object.const_set :Inner, 20 - end - assert_equal ["Inner"], inner + assert_equal ["Inner"], Dependencies.new_constants_in(Object) { + Object.const_set :Inner, 20 + }.map(&:to_s) Object.const_set :OuterAfter, 30 end - assert_equal ["OuterAfter", "OuterBefore"], outer.sort + assert_equal ["OuterAfter", "OuterBefore"], outer.sort.map(&:to_s) assert Dependencies.constant_watch_stack.empty? ensure %w(OuterBefore Inner OuterAfter).each do |name| - Object.send :remove_const, name rescue nil + Object.class_eval { remove_const name if const_defined?(name) } end end @@ -557,7 +556,7 @@ def test_new_constants_in_module assert_equal ["M::OuterAfter", "M::OuterBefore"], outer.sort assert Dependencies.constant_watch_stack.empty? ensure - Object.send :remove_const, :M rescue nil + Object.class_eval { remove_const :M } end def test_new_constants_in_module_using_name @@ -575,12 +574,12 @@ def test_new_constants_in_module_using_name assert_equal ["M::OuterAfter", "M::OuterBefore"], outer.sort assert Dependencies.constant_watch_stack.empty? ensure - Object.send :remove_const, :M rescue nil + Object.class_eval { remove_const :M } end def test_new_constants_in_with_inherited_constants m = Dependencies.new_constants_in(:Object) do - Object.send :include, ModuleWithConstant + Object.class_eval { include ModuleWithConstant } end assert_equal [], m end @@ -670,7 +669,7 @@ def test_autoload_doesnt_shadow_no_method_error_with_relative_constant end ensure - Object.send(:remove_const, :RaisesNoMethodError) if defined?(::RaisesNoMethodError) + Object.class_eval { remove_const :RaisesNoMethodError if const_defined?(:RaisesNoMethodError) } end def test_autoload_doesnt_shadow_no_method_error_with_absolute_constant @@ -683,7 +682,7 @@ def test_autoload_doesnt_shadow_no_method_error_with_absolute_constant end ensure - Object.send(:remove_const, :RaisesNoMethodError) if defined?(::RaisesNoMethodError) + Object.class_eval { remove_const :RaisesNoMethodError if const_defined?(:RaisesNoMethodError) } end def test_autoload_doesnt_shadow_name_error @@ -707,16 +706,16 @@ def test_autoload_doesnt_shadow_name_error end ensure - Object.send(:remove_const, :RaisesNameError) if defined?(::RaisesNameError) + Object.class_eval { remove_const :RaisesNoMethodError if const_defined?(:RaisesNoMethodError) } end def test_remove_constant_handles_double_colon_at_start Object.const_set 'DeleteMe', Module.new DeleteMe.const_set 'OrMe', Module.new - Dependencies.send :remove_constant, "::DeleteMe::OrMe" + Dependencies.remove_constant "::DeleteMe::OrMe" assert ! defined?(DeleteMe::OrMe) assert defined?(DeleteMe) - Dependencies.send :remove_constant, "::DeleteMe" + Dependencies.remove_constant "::DeleteMe" assert ! defined?(DeleteMe) end @@ -730,7 +729,7 @@ def test_load_once_constants_should_not_be_unloaded end ensure Dependencies.load_once_paths = [] - Object.send :remove_const, :A rescue nil + Object.class_eval { remove_const :A if const_defined?(:A) } end def test_load_once_paths_should_behave_when_recursively_loading