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.