aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport/lib/active_support/dependencies.rb
diff options
context:
space:
mode:
Diffstat (limited to 'activesupport/lib/active_support/dependencies.rb')
-rw-r--r--activesupport/lib/active_support/dependencies.rb71
1 files changed, 47 insertions, 24 deletions
diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb
index 6be19771f5..e03e7c30d8 100644
--- a/activesupport/lib/active_support/dependencies.rb
+++ b/activesupport/lib/active_support/dependencies.rb
@@ -30,6 +30,10 @@ module ActiveSupport #:nodoc:
mattr_accessor :loaded
self.loaded = Set.new
+ # Stack of files being loaded.
+ mattr_accessor :loading
+ self.loading = []
+
# Should we load files or require them?
mattr_accessor :mechanism
self.mechanism = ENV['NO_RELOAD'] ? :require : :load
@@ -180,13 +184,14 @@ module ActiveSupport #:nodoc:
Dependencies.load_missing_constant(from_mod, const_name)
end
- # Dependencies assumes the name of the module reflects the nesting (unless
- # it can be proven that is not the case), and the path to the file that
- # defines the constant. Anonymous modules cannot follow these conventions
- # and we assume therefore the user wants to refer to a top-level constant.
+ # We assume that the name of the module reflects the nesting
+ # (unless it can be proven that is not the case) and the path to the file
+ # that defines the constant. Anonymous modules cannot follow these
+ # conventions and therefore we assume that the user wants to refer to a
+ # top-level constant.
def guess_for_anonymous(const_name)
if Object.const_defined?(const_name)
- raise NameError, "#{const_name} cannot be autoloaded from an anonymous class or module"
+ raise NameError.new "#{const_name} cannot be autoloaded from an anonymous class or module", const_name
else
Object
end
@@ -200,7 +205,10 @@ module ActiveSupport #:nodoc:
# Object includes this module.
module Loadable #:nodoc:
def self.exclude_from(base)
- base.class_eval { define_method(:load, Kernel.instance_method(:load)) }
+ base.class_eval do
+ define_method(:load, Kernel.instance_method(:load))
+ private :load
+ end
end
def require_or_load(file_name)
@@ -236,18 +244,6 @@ module ActiveSupport #:nodoc:
raise
end
- def load(file, wrap = false)
- result = false
- load_dependency(file) { result = super }
- result
- end
-
- def require(file)
- result = false
- load_dependency(file) { result = super }
- result
- end
-
# Mark the given constant as unloadable. Unloadable constants are removed
# each time dependencies are cleared.
#
@@ -264,6 +260,20 @@ module ActiveSupport #:nodoc:
def unloadable(const_desc)
Dependencies.mark_for_unload const_desc
end
+
+ private
+
+ def load(file, wrap = false)
+ result = false
+ load_dependency(file) { result = super }
+ result
+ end
+
+ def require(file)
+ result = false
+ load_dependency(file) { result = super }
+ result
+ end
end
# Exception file-blaming.
@@ -316,6 +326,7 @@ module ActiveSupport #:nodoc:
def clear
log_call
loaded.clear
+ loading.clear
remove_unloadable_constants!
end
@@ -328,6 +339,7 @@ module ActiveSupport #:nodoc:
# Record that we've seen this file *before* loading it to avoid an
# infinite loop with mutual dependencies.
loaded << expanded
+ loading << expanded
begin
if load?
@@ -350,6 +362,8 @@ module ActiveSupport #:nodoc:
rescue Exception
loaded.delete expanded
raise
+ ensure
+ loading.pop
end
# Record history *after* loading so first load gets warnings.
@@ -407,7 +421,8 @@ module ActiveSupport #:nodoc:
end
def load_once_path?(path)
- # to_s works around a ruby1.9 issue where #starts_with?(Pathname) will always return false
+ # to_s works around a ruby issue where String#starts_with?(Pathname)
+ # will raise a TypeError: no implicit conversion of Pathname into String
autoload_once_paths.any? { |base| path.starts_with? base.to_s }
end
@@ -473,7 +488,7 @@ module ActiveSupport #:nodoc:
expanded = File.expand_path(file_path)
expanded.sub!(/\.rb\z/, '')
- if loaded.include?(expanded)
+ if loading.include?(expanded)
raise "Circular dependency detected while autoloading constant #{qualified_name}"
else
require_or_load(expanded, qualified_name)
@@ -514,9 +529,9 @@ module ActiveSupport #:nodoc:
end
end
- raise NameError,
- "uninitialized constant #{qualified_name}",
- caller.reject { |l| l.starts_with? __FILE__ }
+ name_error = NameError.new("uninitialized constant #{qualified_name}", const_name)
+ name_error.set_backtrace(caller.reject {|l| l.starts_with? __FILE__ })
+ raise name_error
end
# Remove the constants that have been autoloaded, and those that have been
@@ -665,6 +680,14 @@ module ActiveSupport #:nodoc:
constants = normalized.split('::')
to_remove = constants.pop
+ # Remove the file path from the loaded list.
+ file_path = search_for_file(const.underscore)
+ if file_path
+ expanded = File.expand_path(file_path)
+ expanded.sub!(/\.rb\z/, '')
+ self.loaded.delete(expanded)
+ end
+
if constants.empty?
parent = Object
else
@@ -719,7 +742,7 @@ module ActiveSupport #:nodoc:
protected
def log_call(*args)
if log_activity?
- arg_str = args.collect { |arg| arg.inspect } * ', '
+ arg_str = args.collect(&:inspect) * ', '
/in `([a-z_\?\!]+)'/ =~ caller(1).first
selector = $1 || '<unknown>'
log "called #{selector}(#{arg_str})"