mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
dependencies no longer trigger Kernel#autoload in remove_const [fixes #8213]
This commit is contained in:
parent
77edb7cf55
commit
bff4d8d165
4 changed files with 42 additions and 11 deletions
|
@ -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.
|
||||
|
|
|
@ -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::)+/, '')
|
||||
|
||||
# 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 * '::')
|
||||
constants = normalized.split('::')
|
||||
to_remove = constants.pop
|
||||
parent_name = constants.empty? ? 'Object' : constants.join('::')
|
||||
|
||||
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 }
|
||||
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)
|
||||
|
||||
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
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
ShouldNotBeAutoloaded = 0
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue