lib/active_support/dependencies.rb in activesupport-3.0.20 vs lib/active_support/dependencies.rb in activesupport-3.1.0.beta1
- old
+ new
@@ -3,10 +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/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'
@@ -45,13 +46,10 @@
# An array of qualified constant names that have been loaded. Adding a name to
# this array will cause it to be unloaded the next time Dependencies are cleared.
mattr_accessor :autoloaded_constants
self.autoloaded_constants = []
- mattr_accessor :references
- self.references = {}
-
# An array of constant names that need to be unloaded on every request. Used
# to allow arbitrary constants to be marked for unloading.
mattr_accessor :explicitly_unloadable_constants
self.explicitly_unloadable_constants = []
@@ -62,12 +60,12 @@
# Set to true to enable logging of const_missing and file loads
mattr_accessor :log_activity
self.log_activity = false
# The WatchStack keeps a stack of the modules being watched as files are loaded.
- # If a file in the process of being loaded (parent.rb) triggers the load of
- # another file (child.rb) the stack will ensure that child.rb handles the new
+ # If a file in the process of being loaded (parent.rb) triggers the load of
+ # another file (child.rb) the stack will ensure that child.rb handles the new
# constants.
#
# If child.rb is being autoloaded, its constants will be added to
# autoloaded_constants. If it was being `require`d, they will be discarded.
#
@@ -81,17 +79,17 @@
def initialize
@watching = []
super { |h,k| h[k] = [] }
end
- # return a list of new constants found since the last call to watch_modules
+ # 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_modules
+ # Retrieve the constants that were present under the namespace when watch_namespaces
# was originally called
original_constants = self[namespace].last
mod = Inflector.constantize(namespace) if Dependencies.qualified_const_defined?(namespace)
next unless mod.is_a?(Module)
@@ -113,11 +111,11 @@
constants << ([namespace, suffix] - ["Object"]).join("::")
end
end
constants
ensure
- # A call to new_constants is always called after a call to watch_modules
+ # A call to new_constants is always called after a call to watch_namespaces
pop_modules(@watching.pop)
end
# Add a set of modules to the watch stack, remembering the initial constants
def watch_namespaces(namespaces)
@@ -164,11 +162,11 @@
# Use const_missing to autoload associations so we don't have to
# require_association when using single-table inheritance.
def const_missing(const_name, nesting = nil)
klass_name = name.presence || "Object"
- if !nesting
+ unless nesting
# We'll assume that the nesting of Foo::Bar is ["Foo::Bar", "Foo"]
# even though it might not be, such as in the case of
# class Foo::Bar; Baz; end
nesting = []
klass_name.to_s.scan(/::|$/) { nesting.unshift $` }
@@ -230,19 +228,15 @@
exception.blame_file! file
raise
end
def load(file, *)
- result = false
- load_dependency(file) { result = super }
- result
+ load_dependency(file) { super }
end
def require(file, *)
- result = false
- load_dependency(file) { result = super }
- result
+ load_dependency(file) { super }
end
# Mark the given constant as unloadable. Unloadable constants are removed each
# time dependencies are cleared.
#
@@ -483,10 +477,14 @@
raise ArgumentError, "#{from_mod} is not missing constant #{const_name}!" if local_const_defined?(from_mod, const_name)
qualified_name = qualified_name_for from_mod, const_name
path_suffix = qualified_name.underscore
+ trace = caller.reject {|l| l =~ %r{#{Regexp.escape(__FILE__)}}}
+ name_error = NameError.new("uninitialized constant #{qualified_name}")
+ name_error.set_backtrace(trace)
+
file_path = search_for_file(path_suffix)
if file_path && ! loaded.include?(File.expand_path(file_path)) # We found a matching file to load
require_or_load file_path
raise LoadError, "Expected #{file_path} to define #{qualified_name}" unless local_const_defined?(from_mod, const_name)
@@ -501,57 +499,101 @@
# return constants from from_mod's parents.
begin
return parent.const_missing(const_name)
rescue NameError => e
raise unless e.missing_name? qualified_name_for(parent, const_name)
+ raise name_error
end
+ else
+ raise name_error
end
-
- raise NameError,
- "uninitialized constant #{qualified_name}",
- caller.reject {|l| l.starts_with? __FILE__ }
end
# Remove the constants that have been autoloaded, and those that have been
# marked for unloading. Before each constant is removed a callback is sent
# to its class/module if it implements +before_remove_const+.
#
# The callback implementation should be restricted to cleaning up caches, etc.
- # as the enviroment will be in an inconsistent state, e.g. other constants
+ # as the environment will be in an inconsistent state, e.g. other constants
# may have already been unloaded and not accessible.
def remove_unloadable_constants!
autoloaded_constants.each { |const| remove_constant const }
autoloaded_constants.clear
Reference.clear!
explicitly_unloadable_constants.each { |const| remove_constant const }
end
- class Reference
- @@constants = Hash.new { |h, k| h[k] = Inflector.constantize(k) }
+ class ClassCache
+ def initialize
+ @store = Hash.new { |h, k| h[k] = Inflector.constantize(k) }
+ end
- attr_reader :name
+ def empty?
+ @store.empty?
+ end
- def initialize(name)
- @name = name.to_s
- @@constants[@name] = name if name.respond_to?(:name)
+ def key?(key)
+ @store.key?(key)
end
- def get
- @@constants[@name]
+ 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 self.clear!
- @@constants.clear
+ def [](key)
+ key = key.name if key.respond_to?(:name)
+
+ @store[key]
end
+ alias :get :[]
+
+ class Getter # :nodoc:
+ def initialize(name)
+ @name = name
+ 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
+ self
+ end
+
+ def clear!
+ @store.clear
+ end
end
+ Reference = ClassCache.new
+
def ref(name)
- references[name] ||= Reference.new(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+.
def constantize(name)
- ref(name).get
+ Reference.get(name)
end
# Determine if the given constant has been automatically loaded.
def autoloaded?(desc)
# No name => anonymous module.
@@ -607,10 +649,21 @@
end
return []
end
+ class LoadingModule #:nodoc:
+ # Old style environment.rb referenced this method directly. Please note, it doesn't
+ # actually *do* anything any more.
+ def self.root(*args)
+ if defined?(Rails) && Rails.logger
+ Rails.logger.warn "Your environment.rb uses the old syntax, it may not continue to work in future releases."
+ Rails.logger.warn "For upgrade instructions please see: http://manuals.rubyonrails.com/read/book/19"
+ end
+ end
+ end
+
# Convert the provided const desc to a qualified constant name (as a string).
# A module, class, symbol, or string may be provided.
def to_constant_name(desc) #:nodoc:
case desc
when String then desc.sub(/^::/, '')
@@ -629,29 +682,32 @@
names = const.to_s.sub(/^::(Object)?/, 'Object::').split("::")
to_remove = names.pop
parent = Inflector.constantize(names * '::')
log "removing constant #{const}"
- constantize(const).before_remove_const if constantize(const).respond_to?(:before_remove_const)
+ constantized = constantize(const)
+ constantized.before_remove_const if constantized.respond_to?(:before_remove_const)
parent.instance_eval { remove_const to_remove }
return true
end
protected
def log_call(*args)
- if logger && log_activity
+ if log_activity?
arg_str = args.collect { |arg| arg.inspect } * ', '
/in `([a-z_\?\!]+)'/ =~ caller(1).first
selector = $1 || '<unknown>'
log "called #{selector}(#{arg_str})"
end
end
def log(msg)
- if logger && log_activity
- logger.debug "Dependencies: #{msg}"
- end
+ logger.debug "Dependencies: #{msg}" if log_activity?
+ end
+
+ def log_activity?
+ logger && log_activity
end
end
end
ActiveSupport::Dependencies.hook!