public Method

Dependencies.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.

Source Code

# File active_support/dependencies.rb, line 313
def new_constants_in(*descs)
  log_call(*descs)

  # Build the watch frames. Each frame is a tuple of
  #   [module_name_as_string, constants_defined_elsewhere]
  watch_frames = descs.collect do |desc|
    if desc.is_a? Module
      mod_name = desc.name
      initial_constants = desc.local_constants
    elsif desc.is_a?(String) || desc.is_a?(Symbol)
      mod_name = desc.to_s

      # Handle the case where the module has yet to be defined.
      initial_constants = if qualified_const_defined?(mod_name)
        mod_name.constantize.local_constants
      else
       []
      end
    else
      raise Argument, "#{desc.inspect} does not describe a module!"
    end

    [mod_name, initial_constants]
  end

  constant_watch_stack.concat watch_frames

  aborting = true
  begin
    yield # Now yield to the code that is to define new constants.
    aborting = false
  ensure
    # Find the new constants.
    new_constants = watch_frames.collect do |mod_name, prior_constants|
      # Module still doesn't exist? Treat it as if it has no constants.
      next [] unless qualified_const_defined?(mod_name)

      mod = mod_name.constantize
      next [] unless mod.is_a? Module
      new_constants = mod.local_constants - 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
      end

      new_constants.collect do |suffix|
        mod_name == "Object" ? suffix : "#{mod_name}::#{suffix}"
      end
    end.flatten

    log "New constants: #{new_constants * ', '}"

    if aborting
      log "Error during loading, removing partially loaded constants "
      new_constants.each { |name| remove_constant name }
      new_constants.clear
    end
  end

  return new_constants
ensure
  # Remove the stack frames that we added.
  if defined?(watch_frames) && ! watch_frames.empty?
    frame_ids = watch_frames.collect(&:object_id)
    constant_watch_stack.delete_if do |watch_frame|
      frame_ids.include? watch_frame.object_id
    end
  end
end
Comments

Have your say
Please use Textile formatting (click here for a cheat sheet). Use <code/> and <pre/> for code samples.
Click here to login with OpenID to to post comments.