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