vendor/rails/activesupport/lib/active_support/dependencies.rb in radiant-0.7.2 vs vendor/rails/activesupport/lib/active_support/dependencies.rb in radiant-0.8.0

- old
+ new

@@ -1,10 +1,5 @@ -require 'set' -require 'active_support/core_ext/module/attribute_accessors' -require 'active_support/core_ext/load_error' -require 'active_support/core_ext/kernel' - module ActiveSupport #:nodoc: module Dependencies #:nodoc: extend self # Should we turn on Ruby warnings on the first load of dependent files? @@ -42,18 +37,186 @@ # 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 = [] + # The logger is used for generating information on the action run-time (including benchmarking) if available. + # Can be set to nil for no logging. Compatible with both Ruby's own Logger and Log4r loggers. + mattr_accessor :logger + # Set to true to enable logging of const_missing and file loads mattr_accessor :log_activity self.log_activity = false # An internal stack used to record which constants are loaded by any block. mattr_accessor :constant_watch_stack self.constant_watch_stack = [] + mattr_accessor :constant_watch_stack_mutex + self.constant_watch_stack_mutex = Mutex.new + + # Module includes this module + module ModuleConstMissing #:nodoc: + def self.included(base) #:nodoc: + base.class_eval do + unless defined? const_missing_without_dependencies + alias_method_chain :const_missing, :dependencies + end + end + end + + def self.excluded(base) #:nodoc: + base.class_eval do + if defined? const_missing_without_dependencies + undef_method :const_missing + alias_method :const_missing, :const_missing_without_dependencies + undef_method :const_missing_without_dependencies + end + end + end + + # Use const_missing to autoload associations so we don't have to + # require_association when using single-table inheritance. + def const_missing_with_dependencies(class_id) + ActiveSupport::Dependencies.load_missing_constant self, class_id + end + + def unloadable(const_desc = self) + super(const_desc) + end + end + + # Class includes this module + module ClassConstMissing #:nodoc: + def const_missing(const_name) + if [Object, Kernel].include?(self) || parent == self + super + else + begin + begin + Dependencies.load_missing_constant self, const_name + rescue NameError + parent.send :const_missing, const_name + end + rescue NameError => e + # Make sure that the name we are missing is the one that caused the error + parent_qualified_name = Dependencies.qualified_name_for parent, const_name + raise unless e.missing_name? parent_qualified_name + qualified_name = Dependencies.qualified_name_for self, const_name + raise NameError.new("uninitialized constant #{qualified_name}").copy_blame!(e) + end + end + end + end + + # Object includes this module + module Loadable #:nodoc: + def self.included(base) #:nodoc: + base.class_eval do + unless defined? load_without_new_constant_marking + alias_method_chain :load, :new_constant_marking + end + end + end + + def self.excluded(base) #:nodoc: + base.class_eval do + if defined? load_without_new_constant_marking + undef_method :load + alias_method :load, :load_without_new_constant_marking + undef_method :load_without_new_constant_marking + end + end + end + + def require_or_load(file_name) + Dependencies.require_or_load(file_name) + end + + def require_dependency(file_name) + Dependencies.depend_on(file_name) + end + + def require_association(file_name) + Dependencies.associate_with(file_name) + end + + def load_with_new_constant_marking(file, *extras) #:nodoc: + if Dependencies.load? + Dependencies.new_constants_in(Object) { load_without_new_constant_marking(file, *extras) } + else + load_without_new_constant_marking(file, *extras) + end + rescue Exception => exception # errors from loading file + exception.blame_file! file + raise + end + + def require(file, *extras) #:nodoc: + if Dependencies.load? + Dependencies.new_constants_in(Object) { super } + else + super + end + rescue Exception => exception # errors from required file + exception.blame_file! file + raise + end + + # Mark the given constant as unloadable. Unloadable constants are removed each + # time dependencies are cleared. + # + # Note that marking a constant for unloading need only be done once. Setup + # or init scripts may list each unloadable constant that may need unloading; + # each constant will be removed for every subsequent clear, as opposed to for + # the first clear. + # + # The provided constant descriptor may be a (non-anonymous) module or class, + # or a qualified constant name as a string or symbol. + # + # Returns true if the constant was not previously marked for unloading, false + # otherwise. + def unloadable(const_desc) + Dependencies.mark_for_unload const_desc + end + end + + # Exception file-blaming + module Blamable #:nodoc: + def blame_file!(file) + (@blamed_files ||= []).unshift file + end + + def blamed_files + @blamed_files ||= [] + end + + def describe_blame + return nil if blamed_files.empty? + "This error occurred while loading the following files:\n #{blamed_files.join "\n "}" + end + + def copy_blame!(exc) + @blamed_files = exc.blamed_files.clone + self + end + end + + def hook! + Object.instance_eval { include Loadable } + Module.instance_eval { include ModuleConstMissing } + Class.instance_eval { include ClassConstMissing } + Exception.instance_eval { include Blamable } + true + end + + def unhook! + ModuleConstMissing.excluded(Module) + Loadable.excluded(Object) + true + end + def load? mechanism == :load end def depend_on(file_name, swallow_load_errors = false) @@ -151,16 +314,17 @@ next unless %r{\A#{Regexp.escape(expanded_root)}(/|\\)} =~ expanded_path nesting = expanded_path[(expanded_root.size)..-1] nesting = nesting[1..-1] if nesting && nesting[0] == ?/ next if nesting.blank? - - [ - nesting.camelize, - # Special case: application.rb might define ApplicationControlller. - ('ApplicationController' if nesting == 'application') - ] + nesting_camel = nesting.camelize + begin + qualified_const_defined?(nesting_camel) + rescue NameError + next + end + [ nesting_camel ] end.flatten.compact.uniq end # Search for a file in load_paths matching the provided suffix. def search_for_file(path_suffix) @@ -337,20 +501,22 @@ # Handle the case where the module has yet to be defined. initial_constants = if qualified_const_defined?(mod_name) mod_name.constantize.local_constant_names else - [] + [] end else raise Argument, "#{desc.inspect} does not describe a module!" end [mod_name, initial_constants] end - constant_watch_stack.concat watch_frames + constant_watch_stack_mutex.synchronize do + constant_watch_stack.concat watch_frames + end aborting = true begin yield # Now yield to the code that is to define new constants. aborting = false @@ -363,12 +529,14 @@ mod = mod_name.constantize next [] unless mod.is_a? Module new_constants = mod.local_constant_names - prior_constants # Make sure no other frames takes credit for these constants. - constant_watch_stack.each do |frame_name, constants| - constants.concat new_constants if frame_name == mod_name + constant_watch_stack_mutex.synchronize do + constant_watch_stack.each do |frame_name, constants| + constants.concat new_constants if frame_name == mod_name + end end new_constants.collect do |suffix| mod_name == "Object" ? suffix : "#{mod_name}::#{suffix}" end @@ -385,24 +553,26 @@ return new_constants ensure # Remove the stack frames that we added. if defined?(watch_frames) && ! watch_frames.blank? - frame_ids = watch_frames.collect(&:object_id) - constant_watch_stack.delete_if do |watch_frame| - frame_ids.include? watch_frame.object_id + frame_ids = watch_frames.collect { |frame| frame.object_id } + constant_watch_stack_mutex.synchronize do + constant_watch_stack.delete_if do |watch_frame| + frame_ids.include? watch_frame.object_id + end end end 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_DEFAULT_LOGGER) - RAILS_DEFAULT_LOGGER.warn "Your environment.rb uses the old syntax, it may not continue to work in future releases." - RAILS_DEFAULT_LOGGER.warn "For upgrade instructions please see: http://manuals.rubyonrails.com/read/book/19" + 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). @@ -434,120 +604,22 @@ return true end protected def log_call(*args) - if defined?(RAILS_DEFAULT_LOGGER) && RAILS_DEFAULT_LOGGER && log_activity - arg_str = args.collect(&:inspect) * ', ' + if logger && 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 defined?(RAILS_DEFAULT_LOGGER) && RAILS_DEFAULT_LOGGER && log_activity - RAILS_DEFAULT_LOGGER.debug "Dependencies: #{msg}" + if logger && log_activity + logger.debug "Dependencies: #{msg}" end end end end -Object.instance_eval do - define_method(:require_or_load) { |file_name| ActiveSupport::Dependencies.require_or_load(file_name) } unless Object.respond_to?(:require_or_load) - define_method(:require_dependency) { |file_name| ActiveSupport::Dependencies.depend_on(file_name) } unless Object.respond_to?(:require_dependency) - define_method(:require_association) { |file_name| ActiveSupport::Dependencies.associate_with(file_name) } unless Object.respond_to?(:require_association) -end - -class Module #:nodoc: - # Rename the original handler so we can chain it to the new one - alias :rails_original_const_missing :const_missing - - # Use const_missing to autoload associations so we don't have to - # require_association when using single-table inheritance. - def const_missing(class_id) - ActiveSupport::Dependencies.load_missing_constant self, class_id - end - - def unloadable(const_desc = self) - super(const_desc) - end - -end - -class Class - def const_missing(const_name) - if [Object, Kernel].include?(self) || parent == self - super - else - begin - begin - ActiveSupport::Dependencies.load_missing_constant self, const_name - rescue NameError - parent.send :const_missing, const_name - end - rescue NameError => e - # Make sure that the name we are missing is the one that caused the error - parent_qualified_name = ActiveSupport::Dependencies.qualified_name_for parent, const_name - raise unless e.missing_name? parent_qualified_name - qualified_name = ActiveSupport::Dependencies.qualified_name_for self, const_name - raise NameError.new("uninitialized constant #{qualified_name}").copy_blame!(e) - end - end - end -end - -class Object - alias_method :load_without_new_constant_marking, :load - - def load(file, *extras) #:nodoc: - ActiveSupport::Dependencies.new_constants_in(Object) { super } - rescue Exception => exception # errors from loading file - exception.blame_file! file - raise - end - - def require(file, *extras) #:nodoc: - ActiveSupport::Dependencies.new_constants_in(Object) { super } - rescue Exception => exception # errors from required file - exception.blame_file! file - raise - end - - # Mark the given constant as unloadable. Unloadable constants are removed each - # time dependencies are cleared. - # - # Note that marking a constant for unloading need only be done once. Setup - # or init scripts may list each unloadable constant that may need unloading; - # each constant will be removed for every subsequent clear, as opposed to for - # the first clear. - # - # The provided constant descriptor may be a (non-anonymous) module or class, - # or a qualified constant name as a string or symbol. - # - # Returns true if the constant was not previously marked for unloading, false - # otherwise. - def unloadable(const_desc) - ActiveSupport::Dependencies.mark_for_unload const_desc - end -end - -# Add file-blaming to exceptions -class Exception #:nodoc: - def blame_file!(file) - (@blamed_files ||= []).unshift file - end - - def blamed_files - @blamed_files ||= [] - end - - def describe_blame - return nil if blamed_files.empty? - "This error occurred while loading the following files:\n #{blamed_files.join "\n "}" - end - - def copy_blame!(exc) - @blamed_files = exc.blamed_files.clone - self - end -end +ActiveSupport::Dependencies.hook!