Skip to content

Commit

Permalink
dependencies no longer trigger Kernel#autoload in remove_const [fixes #…
Browse files Browse the repository at this point in the history
  • Loading branch information
fxn committed Nov 15, 2012
1 parent 77edb7c commit bff4d8d
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 13 deletions.
2 changes: 2 additions & 0 deletions activesupport/CHANGELOG.md
@@ -1,5 +1,7 @@
## Rails 4.0.0 (unreleased) ## ## 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* * Simplify mocha integration and remove monkey-patches, bumping mocha to 0.13.0. *James Mead*


* `#as_json` isolates options when encoding a hash. * `#as_json` isolates options when encoding a hash.
Expand Down
44 changes: 31 additions & 13 deletions activesupport/lib/active_support/dependencies.rb
Expand Up @@ -572,7 +572,6 @@ def safe_constantize(name)


# Determine if the given constant has been automatically loaded. # Determine if the given constant has been automatically loaded.
def autoloaded?(desc) def autoloaded?(desc)
# No name => anonymous module.
return false if desc.is_a?(Module) && desc.anonymous? return false if desc.is_a?(Module) && desc.anonymous?
name = to_constant_name desc name = to_constant_name desc
return false unless qualified_const_defined? name return false unless qualified_const_defined? name
Expand Down Expand Up @@ -641,19 +640,38 @@ def to_constant_name(desc) #:nodoc:
end end


def remove_constant(const) #:nodoc: 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 begin
names = const.to_s.sub(/^::(Object)?/, 'Object::').split("::") log "removing constant #{const}"
to_remove = names.pop constantized = parent.const_get(to_remove, false)
parent = Inflector.constantize(names * '::') rescue NameError

log "the constant #{const} is not reachable anymore, skipping"
log "removing constant #{const}" else
constantized = constantize(const) constantized.before_remove_const if constantized.respond_to?(:before_remove_const)
constantized.before_remove_const if constantized.respond_to?(:before_remove_const) parent.instance_eval { remove_const to_remove }
parent.instance_eval { remove_const to_remove } end

end
true
end end


protected protected
Expand Down
@@ -0,0 +1 @@
ShouldNotBeAutoloaded = 0
10 changes: 10 additions & 0 deletions activesupport/test/dependencies_test.rb
Expand Up @@ -928,6 +928,16 @@ def test_remove_constant_handles_double_colon_at_start
assert ! defined?(DeleteMe) assert ! defined?(DeleteMe)
end 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 def test_load_once_constants_should_not_be_unloaded
with_autoloading_fixtures do with_autoloading_fixtures do
ActiveSupport::Dependencies.autoload_once_paths = ActiveSupport::Dependencies.autoload_paths ActiveSupport::Dependencies.autoload_once_paths = ActiveSupport::Dependencies.autoload_paths
Expand Down

0 comments on commit bff4d8d

Please sign in to comment.