lib/active_support/dependencies.rb in activesupport-3.1.12 vs lib/active_support/dependencies.rb in activesupport-3.2.0.rc1
- old
+ new
@@ -3,11 +3,11 @@
require 'pathname'
require 'active_support/core_ext/module/aliasing'
require 'active_support/core_ext/module/attribute_accessors'
require 'active_support/core_ext/module/introspection'
require 'active_support/core_ext/module/anonymous'
-require 'active_support/core_ext/module/deprecation'
+require 'active_support/core_ext/module/qualified_const'
require 'active_support/core_ext/object/blank'
require 'active_support/core_ext/load_error'
require 'active_support/core_ext/name_error'
require 'active_support/core_ext/string/starts_ends_with'
require 'active_support/inflector'
@@ -69,29 +69,39 @@
# If child.rb is being autoloaded, its constants will be added to
# autoloaded_constants. If it was being `require`d, they will be discarded.
#
# This is handled by walking back up the watch stack and adding the constants
# found by child.rb to the list of original constants in parent.rb
- class WatchStack < Hash
+ class WatchStack
+ include Enumerable
+
# @watching is a stack of lists of constants being watched. For instance,
# if parent.rb is autoloaded, the stack will look like [[Object]]. If parent.rb
# then requires namespace/child.rb, the stack will look like [[Object], [Namespace]].
def initialize
@watching = []
- super { |h,k| h[k] = [] }
+ @stack = Hash.new { |h,k| h[k] = [] }
end
+ def each(&block)
+ @stack.each(&block)
+ end
+
+ def watching?
+ !@watching.empty?
+ end
+
# return a list of new constants found since the last call to watch_namespaces
def new_constants
constants = []
# Grab the list of namespaces that we're looking for new constants under
@watching.last.each do |namespace|
# Retrieve the constants that were present under the namespace when watch_namespaces
# was originally called
- original_constants = self[namespace].last
+ original_constants = @stack[namespace].last
mod = Inflector.constantize(namespace) if Dependencies.qualified_const_defined?(namespace)
next unless mod.is_a?(Module)
# Get a list of the constants that were added
@@ -100,11 +110,11 @@
# self[namespace] returns an Array of the constants that are being evaluated
# for that namespace. For instance, if parent.rb requires child.rb, the first
# element of self[Object] will be an Array of the constants that were present
# before parent.rb was required. The second element will be an Array of the
# constants that were present before child.rb was required.
- self[namespace].each do |namespace_constants|
+ @stack[namespace].each do |namespace_constants|
namespace_constants.concat(new_constants)
end
# Normalize the list of new constants, and add them to the list we will return
new_constants.each do |suffix|
@@ -124,17 +134,18 @@
module_name = Dependencies.to_constant_name(namespace)
original_constants = Dependencies.qualified_const_defined?(module_name) ?
Inflector.constantize(module_name).local_constant_names : []
watching << module_name
- self[module_name] << original_constants
+ @stack[module_name] << original_constants
end
@watching << watching
end
+ private
def pop_modules(modules)
- modules.each { |mod| self[mod].pop }
+ modules.each { |mod| @stack[mod].pop }
end
end
# An internal stack used to record which constants are loaded by any block.
mattr_accessor :constant_watch_stack
@@ -217,27 +228,27 @@
def require_association(file_name)
Dependencies.associate_with(file_name)
end
def load_dependency(file)
- if Dependencies.load?
- Dependencies.new_constants_in(Object) { yield }.presence
+ if Dependencies.load? && ActiveSupport::Dependencies.constant_watch_stack.watching?
+ Dependencies.new_constants_in(Object) { yield }
else
yield
end
rescue Exception => exception # errors from loading file
exception.blame_file! file
raise
end
- def load(file, *)
+ def load(file, wrap = false)
result = false
load_dependency(file) { result = super }
result
end
- def require(file, *)
+ def require(file)
result = false
load_dependency(file) { result = super }
result
end
@@ -356,17 +367,18 @@
history << expanded
return result
end
# Is the provided constant path defined?
- def qualified_const_defined?(path)
- names = path.sub(/^::/, '').to_s.split('::')
-
- names.inject(Object) do |mod, name|
- return false unless local_const_defined?(mod, name)
- mod.const_get name
+ if Module.method(:const_defined?).arity == 1
+ def qualified_const_defined?(path)
+ Object.qualified_const_defined?(path.sub(/^::/, ''))
end
+ else
+ def qualified_const_defined?(path)
+ Object.qualified_const_defined?(path.sub(/^::/, ''), false)
+ end
end
if Module.method(:const_defined?).arity == 1
# Does this module define this constant?
# Wrapper to accommodate changing Module#const_defined? in Ruby 1.9
@@ -420,11 +432,12 @@
end
nil
end
def load_once_path?(path)
- autoload_once_paths.any? { |base| path.starts_with? base }
+ # to_s works around a ruby1.9 issue where #starts_with?(Pathname) will always return false
+ autoload_once_paths.any? { |base| path.starts_with? base.to_s }
end
# Attempt to autoload the provided module name by searching for a directory
# matching the expected path suffix. If found, the module is created and assigned
# to +into+'s constants with the name +const_name+. Provided that the directory
@@ -523,77 +536,63 @@
explicitly_unloadable_constants.each { |const| remove_constant const }
end
class ClassCache
def initialize
- @store = Hash.new { |h, k| h[k] = Inflector.constantize(k) }
+ @store = Hash.new
end
def empty?
@store.empty?
end
def key?(key)
@store.key?(key)
end
- def []=(key, value)
- return unless key.respond_to?(:name)
-
- raise(ArgumentError, 'anonymous classes cannot be cached') if key.name.blank?
-
- @store[key.name] = value
- end
-
- def [](key)
+ def get(key)
key = key.name if key.respond_to?(:name)
-
- @store[key]
+ @store[key] ||= Inflector.constantize(key)
end
- alias :get :[]
+ alias :[] :get
- class Getter # :nodoc:
- def initialize(name)
- @name = name
+ def safe_get(key)
+ key = key.name if key.respond_to?(:name)
+ @store[key] || begin
+ klass = Inflector.safe_constantize(key)
+ @store[key] = klass
end
-
- def get
- Reference.get @name
- end
- deprecate :get
end
- def new(name)
- self[name] = name
- Getter.new(name)
- end
- deprecate :new
-
- def store(name)
- self[name] = name
+ def store(klass)
+ return self unless klass.respond_to?(:name)
+ raise(ArgumentError, 'anonymous classes cannot be cached') if klass.name.empty?
+ @store[klass.name] = klass
self
end
def clear!
@store.clear
end
end
Reference = ClassCache.new
- def ref(name)
- Reference.new(name)
- end
- deprecate :ref
-
# Store a reference to a class +klass+.
def reference(klass)
Reference.store klass
end
# Get the reference for class named +name+.
+ # Raises an exception if referenced class does not exist.
def constantize(name)
Reference.get(name)
+ end
+
+ # Get the reference for class named +name+ if one exists.
+ # Otherwise returns nil.
+ def safe_constantize(name)
+ Reference.safe_get(name)
end
# Determine if the given constant has been automatically loaded.
def autoloaded?(desc)
# No name => anonymous module.