aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--activesupport/CHANGELOG.md2
-rw-r--r--activesupport/lib/active_support/dependencies.rb44
-rw-r--r--activesupport/test/autoloading_fixtures/should_not_be_required.rb1
-rw-r--r--activesupport/test/dependencies_test.rb10
4 files changed, 44 insertions, 13 deletions
diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md
index 2bbc41296f..7daa0d5bca 100644
--- a/activesupport/CHANGELOG.md
+++ b/activesupport/CHANGELOG.md
@@ -1,5 +1,7 @@
## Rails 4.0.0 (unreleased) ##
+* Dependencies no longer trigger Kernel#autoload in remove_const [fixes #8213]. *Xavier Noria*
+
* Simplify mocha integration and remove monkey-patches, bumping mocha to 0.13.0. *James Mead*
* `#as_json` isolates options when encoding a hash.
diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb
index 42746582fa..00b1b3ec98 100644
--- a/activesupport/lib/active_support/dependencies.rb
+++ b/activesupport/lib/active_support/dependencies.rb
@@ -572,7 +572,6 @@ module ActiveSupport #:nodoc:
# Determine if the given constant has been automatically loaded.
def autoloaded?(desc)
- # No name => anonymous module.
return false if desc.is_a?(Module) && desc.anonymous?
name = to_constant_name desc
return false unless qualified_const_defined? name
@@ -641,19 +640,38 @@ module ActiveSupport #:nodoc:
end
def remove_constant(const) #:nodoc:
- return false unless qualified_const_defined? const
+ # Normalize ::Foo, ::Object::Foo, Object::Foo, Object::Object::Foo, etc. as Foo.
+ normalized = const.to_s.sub(/\A::/, '')
+ normalized.sub!(/\A(Object::)+/, '')
+
+ constants = normalized.split('::')
+ to_remove = constants.pop
+ parent_name = constants.empty? ? 'Object' : constants.join('::')
+
+ if parent = safe_constantize(parent_name)
+ # In an autoloaded user.rb like this
+ #
+ # autoload :Foo, 'foo'
+ #
+ # class User < ActiveRecord::Base
+ # end
+ #
+ # we correctly register "Foo" as being autoloaded. But if the app
+ # does not use the "Foo" constant we need to be careful not to
+ # trigger loading "foo". If the autoload has not been triggered
+ # we already know there is nothing to remove so just return.
+ return if parent.autoload?(to_remove)
- # Normalize ::Foo, Foo, Object::Foo, and ::Object::Foo to Object::Foo
- names = const.to_s.sub(/^::(Object)?/, 'Object::').split("::")
- to_remove = names.pop
- parent = Inflector.constantize(names * '::')
-
- log "removing constant #{const}"
- constantized = constantize(const)
- constantized.before_remove_const if constantized.respond_to?(:before_remove_const)
- parent.instance_eval { remove_const to_remove }
-
- true
+ begin
+ log "removing constant #{const}"
+ constantized = parent.const_get(to_remove, false)
+ rescue NameError
+ log "the constant #{const} is not reachable anymore, skipping"
+ else
+ constantized.before_remove_const if constantized.respond_to?(:before_remove_const)
+ parent.instance_eval { remove_const to_remove }
+ end
+ end
end
protected
diff --git a/activesupport/test/autoloading_fixtures/should_not_be_required.rb b/activesupport/test/autoloading_fixtures/should_not_be_required.rb
new file mode 100644
index 0000000000..1fcf170cc5
--- /dev/null
+++ b/activesupport/test/autoloading_fixtures/should_not_be_required.rb
@@ -0,0 +1 @@
+ShouldNotBeAutoloaded = 0
diff --git a/activesupport/test/dependencies_test.rb b/activesupport/test/dependencies_test.rb
index 670a04e5df..6e5a6f71e2 100644
--- a/activesupport/test/dependencies_test.rb
+++ b/activesupport/test/dependencies_test.rb
@@ -928,6 +928,16 @@ class DependenciesTest < ActiveSupport::TestCase
assert ! defined?(DeleteMe)
end
+ def test_remove_constant_does_not_trigger_loading_autoloads
+ constant = 'ShouldNotBeAutoloaded'
+ Object.class_eval do
+ autoload constant, File.expand_path('../autoloading_fixtures/should_not_be_required', __FILE__)
+ end
+ ActiveSupport::Dependencies.remove_constant(constant)
+
+ assert Object.autoload?(constant), "Kernel#autoload of #{constant} has been triggered by remove_const"
+ end
+
def test_load_once_constants_should_not_be_unloaded
with_autoloading_fixtures do
ActiveSupport::Dependencies.autoload_once_paths = ActiveSupport::Dependencies.autoload_paths