module Puppet::Pops
module Loader
# BaseLoader
# ===
# An abstract implementation of Loader
#
# A derived class should implement `find(typed_name)` and set entries, and possible handle "miss caching".
#
# @api private
#
class BaseLoader < Loader
# The parent loader
attr_reader :parent
def initialize(parent_loader, loader_name)
super(loader_name)
@parent = parent_loader # the higher priority loader to consult
@named_values = {} # hash name => NamedEntry
@last_result = nil # the value of the last name (optimization)
end
def discover(type, error_collector = nil, name_authority = Pcore::RUNTIME_NAME_AUTHORITY, &block)
result = []
@named_values.each_pair do |key, entry|
result << key unless entry.nil? || entry.value.nil? || key.type != type || (block_given? && !yield(key))
end
result.concat(parent.discover(type, error_collector, name_authority, &block))
result.uniq!
result
end
# @api public
#
def load_typed(typed_name)
# The check for "last queried name" is an optimization when a module searches. First it checks up its parent
# chain, then itself, and then delegates to modules it depends on.
# These modules are typically parented by the same
# loader as the one initiating the search. It is inefficient to again try to search the same loader for
# the same name.
if @last_result.nil? || typed_name != @last_result.typed_name
@last_result = internal_load(typed_name)
else
@last_result
end
end
# @api public
#
def loaded_entry(typed_name, check_dependencies = false)
if @named_values.has_key?(typed_name)
@named_values[typed_name]
elsif parent
parent.loaded_entry(typed_name, check_dependencies)
else
nil
end
end
# This method is final (subclasses should not override it)
#
# @api private
#
def get_entry(typed_name)
@named_values[typed_name]
end
# @api private
#
def set_entry(typed_name, value, origin = nil)
# It is never ok to redefine in the very same loader unless redefining a 'not found'
entry = @named_values[typed_name]
if entry
fail_redefine(entry) unless entry.value.nil?
end
# Check if new entry shadows existing entry and fail
# (unless special loader allows shadowing)
if typed_name.type == :type && !allow_shadowing?
entry = loaded_entry(typed_name)
if entry
fail_redefine(entry) unless entry.value.nil? #|| entry.value == value
end
end
@last_result = Loader::NamedEntry.new(typed_name, value, origin)
@named_values[typed_name] = @last_result
end
# @api private
#
def add_entry(type, name, value, origin)
set_entry(TypedName.new(type, name), value, origin)
end
# @api private
#
def remove_entry(typed_name)
unless @named_values.delete(typed_name).nil?
@last_result = nil unless @last_result.nil? || typed_name != @last_result.typed_name
end
end
# Promotes an already created entry (typically from another loader) to this loader
#
# @api private
#
def promote_entry(named_entry)
typed_name = named_entry.typed_name
entry = @named_values[typed_name]
if entry then fail_redefine(entry); end
@named_values[typed_name] = named_entry
end
protected
def allow_shadowing?
false
end
private
def fail_redefine(entry)
origin_info = entry.origin ? _("Originally set %{original}.") % { original: origin_label(entry.origin) } : _("Set at unknown location")
raise ArgumentError, _("Attempt to redefine entity '%{name}'. %{origin_info}") % { name: entry.typed_name, origin_info: origin_info }
end
# TODO: Should not really be here?? - TODO: A Label provider ? semantics for the URI?
#
def origin_label(origin)
if origin && origin.is_a?(URI)
format_uri(origin)
elsif origin.respond_to?(:uri)
format_uri(origin.uri)
else
origin
end
end
def format_uri(uri)
(uri.scheme == 'puppet' ? 'by ' : 'at ') + uri.to_s.sub(/^puppet:/,'')
end
# loads in priority order:
# 1. already loaded here
# 2. load from parent
# 3. find it here
# 4. give up
#
def internal_load(typed_name)
# avoid calling get_entry by looking it up
te = @named_values[typed_name]
return te unless te.nil? || te.value.nil?
te = parent.load_typed(typed_name)
return te unless te.nil? || te.value.nil?
# Under some circumstances, the call to the parent loader will have resulted in files being
# parsed that in turn contained references to the requested entity and hence, caused a
# recursive call into this loader. This means that the entry might be present now, so a new
# check must be made.
te = @named_values[typed_name]
te.nil? || te.value.nil? ? find(typed_name) : te
end
end
end
end
Anons79 File Manager Version 1.0, Coded By Anons79
Email: [email protected]