Module: Dependencies
Child modules and classes
Class Dependencies::LoadingModule
Public Instance Methods
associate_with (file_name)
# File vendor/rails/activesupport/lib/active_support/dependencies.rb, line 65 65: def associate_with(file_name) 66: depend_on(file_name, true) 67: end
autoload_module! (into, const_name, qualified_name, path_suffix)
Attempt to autoload the provided module name by searching for a directory matching the expect path suffix. If found, the module is created and assigned to into‘s constants with the name const_name. Provided that the directory was loaded from a reloadable base path, it is added to the set of constants that are to be unloaded.
# File vendor/rails/activesupport/lib/active_support/dependencies.rb, line 180 180: def autoload_module!(into, const_name, qualified_name, path_suffix) 181: return nil unless base_path = autoloadable_module?(path_suffix) 182: mod = Module.new 183: into.const_set const_name, mod 184: autoloaded_constants << qualified_name unless load_once_paths.include?(base_path) 185: return mod 186: end
autoloadable_module? (path_suffix)
Does the provided path_suffix correspond to an autoloadable module? Instead of returning a boolean, the autoload base for this module is returned.
# File vendor/rails/activesupport/lib/active_support/dependencies.rb, line 164 164: def autoloadable_module?(path_suffix) 165: load_paths.each do |load_path| 166: return load_path if File.directory? File.join(load_path, path_suffix) 167: end 168: nil 169: end
autoloaded? (desc)
Determine if the given constant has been automatically loaded.
# File vendor/rails/activesupport/lib/active_support/dependencies.rb, line 279 279: def autoloaded?(desc) 280: # No name => anonymous module. 281: return false if desc.is_a?(Module) && desc.name.blank? 282: name = to_constant_name desc 283: return false unless qualified_const_defined? name 284: return autoloaded_constants.include?(name) 285: end
clear ()
# File vendor/rails/activesupport/lib/active_support/dependencies.rb, line 69 69: def clear 70: log_call 71: loaded.clear 72: remove_unloadable_constants! 73: end
depend_on (file_name, swallow_load_errors = false)
# File vendor/rails/activesupport/lib/active_support/dependencies.rb, line 58 58: def depend_on(file_name, swallow_load_errors = false) 59: path = search_for_file(file_name) 60: require_or_load(path || file_name) 61: rescue LoadError 62: raise unless swallow_load_errors 63: end
load? ()
# File vendor/rails/activesupport/lib/active_support/dependencies.rb, line 54 54: def load? 55: mechanism == :load 56: end
load_file (path, const_paths = loadable_constants_for_path(path))
Load the file at the provided path. const_paths is a set of qualified constant names. When loading the file, Dependencies will watch for the addition of these constants. Each that is defined will be marked as autoloaded, and will be removed when Dependencies.clear is next called.
If the second parameter is left off, then Dependencies will construct a set of names that the file at path may define. See loadable_constants_for_path for more details.
# File vendor/rails/activesupport/lib/active_support/dependencies.rb, line 196 196: def load_file(path, const_paths = loadable_constants_for_path(path)) 197: log_call path, const_paths 198: const_paths = [const_paths].compact unless const_paths.is_a? Array 199: parent_paths = const_paths.collect { |const_path| /(.*)::[^:]+\Z/ =~ const_path ? $1 : :Object } 200: 201: result = nil 202: newly_defined_paths = new_constants_in(*parent_paths) do 203: result = load_without_new_constant_marking path 204: end 205: 206: autoloaded_constants.concat newly_defined_paths unless load_once_path?(path) 207: autoloaded_constants.uniq! 208: log "loading #{path} defined #{newly_defined_paths * ', '}" unless newly_defined_paths.empty? 209: return result 210: end
load_missing_constant (from_mod, const_name)
Load the constant named const_name which is missing from from_mod. If it is not possible to load the constant into from_mod, try its parent module using const_missing.
# File vendor/rails/activesupport/lib/active_support/dependencies.rb, line 221 221: def load_missing_constant(from_mod, const_name) 222: log_call from_mod, const_name 223: if from_mod == Kernel 224: if ::Object.const_defined?(const_name) 225: log "Returning Object::#{const_name} for Kernel::#{const_name}" 226: return ::Object.const_get(const_name) 227: else 228: log "Substituting Object for Kernel" 229: from_mod = Object 230: end 231: end 232: 233: # If we have an anonymous module, all we can do is attempt to load from Object. 234: from_mod = Object if from_mod.name.blank? 235: 236: unless qualified_const_defined?(from_mod.name) && from_mod.name.constantize.object_id == from_mod.object_id 237: raise ArgumentError, "A copy of #{from_mod} has been removed from the module tree but is still active!" 238: end 239: 240: raise ArgumentError, "#{from_mod} is not missing constant #{const_name}!" if from_mod.const_defined?(const_name) 241: 242: qualified_name = qualified_name_for from_mod, const_name 243: path_suffix = qualified_name.underscore 244: name_error = NameError.new("uninitialized constant #{qualified_name}") 245: 246: file_path = search_for_file(path_suffix) 247: if file_path && ! loaded.include?(File.expand_path(file_path)) # We found a matching file to load 248: require_or_load file_path 249: raise LoadError, "Expected #{file_path} to define #{qualified_name}" unless from_mod.const_defined?(const_name) 250: return from_mod.const_get(const_name) 251: elsif mod = autoload_module!(from_mod, const_name, qualified_name, path_suffix) 252: return mod 253: elsif (parent = from_mod.parent) && parent != from_mod && 254: ! from_mod.parents.any? { |p| p.const_defined?(const_name) } 255: # If our parents do not have a constant named +const_name+ then we are free 256: # to attempt to load upwards. If they do have such a constant, then this 257: # const_missing must be due to from_mod::const_name, which should not 258: # return constants from from_mod's parents. 259: begin 260: return parent.const_missing(const_name) 261: rescue NameError => e 262: raise unless e.missing_name? qualified_name_for(parent, const_name) 263: raise name_error 264: end 265: else 266: raise name_error 267: end 268: end
load_once_path? (path)
# File vendor/rails/activesupport/lib/active_support/dependencies.rb, line 171 171: def load_once_path?(path) 172: load_once_paths.any? { |base| path.starts_with? base } 173: end
loadable_constants_for_path (path, bases = load_paths)
Given path, a filesystem path to a ruby file, return an array of constant paths which would cause Dependencies to attempt to load this file.
# File vendor/rails/activesupport/lib/active_support/dependencies.rb, line 132 132: def loadable_constants_for_path(path, bases = load_paths) 133: path = $1 if path =~ /\A(.*)\.rb\Z/ 134: expanded_path = File.expand_path(path) 135: 136: bases.collect do |root| 137: expanded_root = File.expand_path(root) 138: next unless %r{\A#{Regexp.escape(expanded_root)}(/|\\)} =~ expanded_path 139: 140: nesting = expanded_path[(expanded_root.size)..-1] 141: nesting = nesting[1..-1] if nesting && nesting[0] == ?/ 142: next if nesting.blank? 143: 144: [ 145: nesting.camelize, 146: # Special case: application.rb might define ApplicationControlller. 147: ('ApplicationController' if nesting == 'application') 148: ] 149: end.flatten.compact.uniq 150: end
mark_for_unload (const_desc)
Mark the provided constant name for unloading. This constant will be unloaded on each request, not just the next one.
# File vendor/rails/activesupport/lib/active_support/dependencies.rb, line 295 295: def mark_for_unload(const_desc) 296: name = to_constant_name const_desc 297: if explicitly_unloadable_constants.include? name 298: return false 299: else 300: explicitly_unloadable_constants << name 301: return true 302: end 303: end
new_constants_in (*descs) {|| ...}
Run the provided block and detect the new constants that were loaded during its execution. Constants may only be regarded as ‘new’ once — so if the block calls new_constants_in again, then the constants defined within the inner call will not be reported in this one.
If the provided block does not run to completion, and instead raises an exception, any new constants are regarded as being only partially defined and will be removed immediately.
# File vendor/rails/activesupport/lib/active_support/dependencies.rb, line 313 313: def new_constants_in(*descs) 314: log_call(*descs) 315: 316: # Build the watch frames. Each frame is a tuple of 317: # [module_name_as_string, constants_defined_elsewhere] 318: watch_frames = descs.collect do |desc| 319: if desc.is_a? Module 320: mod_name = desc.name 321: initial_constants = desc.local_constant_names 322: elsif desc.is_a?(String) || desc.is_a?(Symbol) 323: mod_name = desc.to_s 324: 325: # Handle the case where the module has yet to be defined. 326: initial_constants = if qualified_const_defined?(mod_name) 327: mod_name.constantize.local_constant_names 328: else 329: [] 330: end 331: else 332: raise Argument, "#{desc.inspect} does not describe a module!" 333: end 334: 335: [mod_name, initial_constants] 336: end 337: 338: constant_watch_stack.concat watch_frames 339: 340: aborting = true 341: begin 342: yield # Now yield to the code that is to define new constants. 343: aborting = false 344: ensure 345: # Find the new constants. 346: new_constants = watch_frames.collect do |mod_name, prior_constants| 347: # Module still doesn't exist? Treat it as if it has no constants. 348: next [] unless qualified_const_defined?(mod_name) 349: 350: mod = mod_name.constantize 351: next [] unless mod.is_a? Module 352: new_constants = mod.local_constant_names - prior_constants 353: 354: # Make sure no other frames takes credit for these constants. 355: constant_watch_stack.each do |frame_name, constants| 356: constants.concat new_constants if frame_name == mod_name 357: end 358: 359: new_constants.collect do |suffix| 360: mod_name == "Object" ? suffix : "#{mod_name}::#{suffix}" 361: end 362: end.flatten 363: 364: log "New constants: #{new_constants * ', '}" 365: 366: if aborting 367: log "Error during loading, removing partially loaded constants " 368: new_constants.each { |name| remove_constant name } 369: new_constants.clear 370: end 371: end 372: 373: return new_constants 374: ensure 375: # Remove the stack frames that we added. 376: if defined?(watch_frames) && ! watch_frames.empty? 377: frame_ids = watch_frames.collect(&:object_id) 378: constant_watch_stack.delete_if do |watch_frame| 379: frame_ids.include? watch_frame.object_id 380: end 381: end 382: end
qualified_const_defined? (path)
Is the provided constant path defined?
# File vendor/rails/activesupport/lib/active_support/dependencies.rb, line 113 113: def qualified_const_defined?(path) 114: raise NameError, "#{path.inspect} is not a valid constant name!" unless 115: /^(::)?([A-Z]\w*)(::[A-Z]\w*)*$/ =~ path 116: 117: names = path.to_s.split('::') 118: names.shift if names.first.empty? 119: 120: # We can't use defined? because it will invoke const_missing for the parent 121: # of the name we are checking. 122: names.inject(Object) do |mod, name| 123: return false unless mod.const_defined? name 124: mod.const_get name 125: end 126: return true 127: end
qualified_name_for (mod, name)
Return the constant path for the provided parent and constant name.
# File vendor/rails/activesupport/lib/active_support/dependencies.rb, line 213 213: def qualified_name_for(mod, name) 214: mod_name = to_constant_name mod 215: (%w(Object Kernel).include? mod_name) ? name.to_s : "#{mod_name}::#{name}" 216: end
remove_constant (const)
# File vendor/rails/activesupport/lib/active_support/dependencies.rb, line 408 408: def remove_constant(const) #nodoc 409: return false unless qualified_const_defined? const 410: 411: const = $1 if /\A::(.*)\Z/ =~ const.to_s 412: names = const.to_s.split('::') 413: if names.size == 1 # It's under Object 414: parent = Object 415: else 416: parent = (names[0..-2] * '::').constantize 417: end 418: 419: log "removing constant #{const}" 420: parent.instance_eval { remove_const names.last } 421: return true 422: end
remove_unloadable_constants! ()
Remove the constants that have been autoloaded, and those that have been marked for unloading.
# File vendor/rails/activesupport/lib/active_support/dependencies.rb, line 272 272: def remove_unloadable_constants! 273: autoloaded_constants.each { |const| remove_constant const } 274: autoloaded_constants.clear 275: explicitly_unloadable_constants.each { |const| remove_constant const } 276: end
require_or_load (file_name, const_path = nil)
# File vendor/rails/activesupport/lib/active_support/dependencies.rb, line 75 75: def require_or_load(file_name, const_path = nil) 76: log_call file_name, const_path 77: file_name = $1 if file_name =~ /^(.*)\.rb$/ 78: expanded = File.expand_path(file_name) 79: return if loaded.include?(expanded) 80: 81: # Record that we've seen this file *before* loading it to avoid an 82: # infinite loop with mutual dependencies. 83: loaded << expanded 84: 85: if load? 86: log "loading #{file_name}" 87: begin 88: # Enable warnings iff this file has not been loaded before and 89: # warnings_on_first_load is set. 90: load_args = ["#{file_name}.rb"] 91: load_args << const_path unless const_path.nil? 92: 93: if !warnings_on_first_load or history.include?(expanded) 94: result = load_file(*load_args) 95: else 96: enable_warnings { result = load_file(*load_args) } 97: end 98: rescue Exception 99: loaded.delete expanded 100: raise 101: end 102: else 103: log "requiring #{file_name}" 104: result = require file_name 105: end 106: 107: # Record history *after* loading so first load gets warnings. 108: history << expanded 109: return result 110: end
search_for_file (path_suffix)
Search for a file in load_paths matching the provided suffix.
# File vendor/rails/activesupport/lib/active_support/dependencies.rb, line 153 153: def search_for_file(path_suffix) 154: path_suffix = path_suffix + '.rb' unless path_suffix.ends_with? '.rb' 155: load_paths.each do |root| 156: path = File.join(root, path_suffix) 157: return path if File.file? path 158: end 159: nil # Gee, I sure wish we had first_match ;-) 160: end
to_constant_name (desc)
Convert the provided const desc to a qualified constant name (as a string). A module, class, symbol, or string may be provided.
# File vendor/rails/activesupport/lib/active_support/dependencies.rb, line 397 397: def to_constant_name(desc) #nodoc 398: name = case desc 399: when String then desc.starts_with?('::') ? desc[2..-1] : desc 400: when Symbol then desc.to_s 401: when Module 402: raise ArgumentError, "Anonymous modules have no name to be referenced by" if desc.name.blank? 403: desc.name 404: else raise TypeError, "Not a valid constant descriptor: #{desc.inspect}" 405: end 406: end
will_unload? (const_desc)
Will the provided constant descriptor be unloaded?
# File vendor/rails/activesupport/lib/active_support/dependencies.rb, line 288 288: def will_unload?(const_desc) 289: autoloaded?(desc) || 290: explicitly_unloadable_constants.include?(to_constant_name(const_desc)) 291: end
Protected Instance Methods
log (msg)
# File vendor/rails/activesupport/lib/active_support/dependencies.rb, line 432 432: def log(msg) 433: if defined?(RAILS_DEFAULT_LOGGER) && RAILS_DEFAULT_LOGGER && log_activity 434: RAILS_DEFAULT_LOGGER.debug "Dependencies: #{msg}" 435: end 436: end
log_call (*args)
# File vendor/rails/activesupport/lib/active_support/dependencies.rb, line 425 425: def log_call(*args) 426: arg_str = args.collect(&:inspect) * ', ' 427: /in `([a-z_\?\!]+)'/ =~ caller(1).first 428: selector = $1 || '<unknown>' 429: log "called #{selector}(#{arg_str})" 430: end