class Puppet::Pops::Types::PTypeSetType

Constants

DEFAULT
TYPE_STRING_OR_RANGE
TYPE_STRING_OR_VERSION
TYPE_TYPESET_I12N
TYPE_TYPE_REFERENCE_I12N

Attributes

annotations[R]
name[R]
name_authority[R]
pcore_uri[R]
pcore_version[R]
references[R]
types[R]
version[R]

Public Class Methods

new(name_or_init_hash, init_hash_expression = nil, name_authority = nil) click to toggle source

Initialize a TypeSet Type instance. The initialization will use either a name and an initialization hash expression, or a fully resolved initialization hash.

@overload initialize(name, init_hash_expression)

Used when the TypeSet type is loaded using a type alias expression. When that happens, it is important that
the actual resolution of the expression is deferred until all definitions have been made known to the current
loader. The package will then be resolved when it is loaded by the {TypeParser}. "resolved" here, means that
the hash expression is fully resolved, and then passed to the {#_pcore_init_from_hash} method.
@param name [String] The name of the type set
@param init_hash_expression [Model::LiteralHash] The hash describing the TypeSet features
@param name_authority [String] The default name authority for the type set

@overload initialize(init_hash)

Used when the package is created by the {TypeFactory}. The init_hash must be fully resolved.
@param init_hash [Hash{String=>Object}] The hash describing the TypeSet features

@api private

    # File lib/puppet/pops/types/p_type_set_type.rb
 90 def initialize(name_or_init_hash, init_hash_expression = nil, name_authority = nil)
 91   @types = EMPTY_HASH
 92   @references = EMPTY_HASH
 93 
 94   if name_or_init_hash.is_a?(Hash)
 95     _pcore_init_from_hash(name_or_init_hash)
 96   else
 97     # Creation using "type XXX = TypeSet[{}]". This means that the name is given
 98     @name = TypeAsserter.assert_instance_of('TypeSet name', Pcore::TYPE_QUALIFIED_REFERENCE, name_or_init_hash)
 99     @name_authority = TypeAsserter.assert_instance_of('TypeSet name_authority', Pcore::TYPE_URI, name_authority, true)
100     @init_hash_expression = init_hash_expression
101   end
102 end
register_ptype(loader, ir) click to toggle source
   # File lib/puppet/pops/types/p_type_set_type.rb
60 def self.register_ptype(loader, ir)
61   create_ptype(loader, ir, 'AnyType', '_pcore_init_hash' => TYPE_TYPESET_I12N.resolve(loader))
62 end

Public Instance Methods

[](qname) click to toggle source

Resolve a type in this type set using a qualified name. The resolved type may either be a type defined in this type set or a type defined in a type set that is referenced by this type set (nesting may occur to any level). The name resolution is case insensitive.

@param qname [String,Loader::TypedName] the qualified name of the type to resolve @return [PAnyType,nil] the resolved type, or `nil` in case no type could be found

@api public

    # File lib/puppet/pops/types/p_type_set_type.rb
192 def [](qname)
193   if qname.is_a?(Loader::TypedName)
194     return nil unless qname.type == :type && qname.name_authority == @name_authority
195     qname = qname.name
196   end
197 
198   type = @types[qname] || @types[@dc_to_cc_map[qname.downcase]]
199   if type.nil? && !@references.empty?
200     segments = qname.split(TypeFormatter::NAME_SEGMENT_SEPARATOR)
201     first = segments[0]
202     type_set_ref = @references[first] || @references[@dc_to_cc_map[first.downcase]]
203     if type_set_ref.nil?
204       nil
205     else
206       type_set = type_set_ref.type_set
207       case segments.size
208       when 1
209         type_set
210       when 2
211         type_set[segments[1]]
212       else
213         segments.shift
214         type_set[segments.join(TypeFormatter::NAME_SEGMENT_SEPARATOR)]
215       end
216     end
217   else
218     type
219   end
220 end
_pcore_init_from_hash(init_hash) click to toggle source

@api private

    # File lib/puppet/pops/types/p_type_set_type.rb
105 def _pcore_init_from_hash(init_hash)
106   TypeAsserter.assert_instance_of('TypeSet initializer', TYPE_TYPESET_I12N, init_hash)
107 
108   # Name given to the loader have higher precedence than a name declared in the type
109   @name ||= init_hash[KEY_NAME].freeze
110   @name_authority ||= init_hash[KEY_NAME_AUTHORITY].freeze
111 
112   @pcore_version = PSemVerType.convert(init_hash[Pcore::KEY_PCORE_VERSION]).freeze
113   unless Pcore::PARSABLE_PCORE_VERSIONS.include?(@pcore_version)
114     raise ArgumentError,
115       "The pcore version for TypeSet '#{@name}' is not understood by this runtime. Expected range #{Pcore::PARSABLE_PCORE_VERSIONS}, got #{@pcore_version}"
116   end
117 
118   @pcore_uri = init_hash[Pcore::KEY_PCORE_URI].freeze
119   @version = PSemVerType.convert(init_hash[KEY_VERSION])
120   @types = init_hash[KEY_TYPES] || EMPTY_HASH
121   @types.freeze
122 
123   # Map downcase names to their camel-cased equivalent
124   @dc_to_cc_map = {}
125   @types.keys.each { |key| @dc_to_cc_map[key.downcase] = key }
126 
127   refs = init_hash[KEY_REFERENCES]
128   if refs.nil?
129     @references = EMPTY_HASH
130   else
131     ref_map = {}
132     root_map = Hash.new { |h, k| h[k] = {} }
133     refs.each do |ref_alias, ref|
134       ref = TypeSetReference.new(self, ref)
135 
136       # Protect against importing the exact same name_authority/name combination twice if the version ranges intersect
137       ref_name = ref.name
138       ref_na = ref.name_authority || @name_authority
139       na_roots = root_map[ref_na]
140 
141       ranges = na_roots[ref_name]
142       if ranges.nil?
143         na_roots[ref_name] = [ref.version_range]
144       else
145         unless ranges.all? { |range| (range & ref.version_range).nil? }
146           raise ArgumentError, "TypeSet '#{@name}' references TypeSet '#{ref_na}/#{ref_name}' more than once using overlapping version ranges"
147         end
148         ranges << ref.version_range
149       end
150 
151       if ref_map.has_key?(ref_alias)
152         raise ArgumentError, "TypeSet '#{@name}' references a TypeSet using alias '#{ref_alias}' more than once"
153       end
154       if @types.has_key?(ref_alias)
155         raise ArgumentError, "TypeSet '#{@name}' references a TypeSet using alias '#{ref_alias}'. The alias collides with the name of a declared type"
156       end
157       ref_map[ref_alias] = ref
158 
159       @dc_to_cc_map[ref_alias.downcase] = ref_alias
160       ref_map[ref_alias] = ref
161     end
162     @references = ref_map.freeze
163   end
164   @dc_to_cc_map.freeze
165   init_annotatable(init_hash)
166 end
_pcore_init_hash() click to toggle source

Produce a hash suitable for the initializer @return [Hash{String => Object}] the initialization hash

@api private

Calls superclass method Puppet::Pops::Types::Annotatable#_pcore_init_hash
    # File lib/puppet/pops/types/p_type_set_type.rb
172 def _pcore_init_hash
173   result = super()
174   result[Pcore::KEY_PCORE_URI] = @pcore_uri unless @pcore_uri.nil?
175   result[Pcore::KEY_PCORE_VERSION] =  @pcore_version.to_s
176   result[KEY_NAME_AUTHORITY] = @name_authority unless @name_authority.nil?
177   result[KEY_NAME] = @name
178   result[KEY_VERSION] = @version.to_s unless @version.nil?
179   result[KEY_TYPES] = @types unless @types.empty?
180   result[KEY_REFERENCES] = Hash[@references.map { |ref_alias, ref| [ref_alias, ref._pcore_init_hash] }] unless @references.empty?
181   result
182 end
accept(visitor, guard) click to toggle source
Calls superclass method Puppet::Pops::Types::PMetaType#accept
    # File lib/puppet/pops/types/p_type_set_type.rb
248 def accept(visitor, guard)
249   super
250   @types.each_value { |type| type.accept(visitor, guard) }
251   @references.each_value { |ref| ref.accept(visitor, guard) }
252 end
defines_type?(t) click to toggle source
    # File lib/puppet/pops/types/p_type_set_type.rb
222 def defines_type?(t)
223   !@types.key(t).nil?
224 end
eql?(o) click to toggle source
    # File lib/puppet/pops/types/p_type_set_type.rb
348 def eql?(o)
349   self.class == o.class && @name_authority == o.name_authority && @name == o.name && @version == o.version
350 end
hash() click to toggle source
    # File lib/puppet/pops/types/p_type_set_type.rb
344 def hash
345   @name_authority.hash ^ @name.hash ^ @version.hash
346 end
instance?(o, guard = nil) click to toggle source
    # File lib/puppet/pops/types/p_type_set_type.rb
352 def instance?(o, guard = nil)
353   o.is_a?(PTypeSetType)
354 end
label() click to toggle source

@api private

    # File lib/puppet/pops/types/p_type_set_type.rb
255 def label
256   "TypeSet '#{@name}'"
257 end
name_for(t, default_name) click to toggle source

Returns the name by which the given type is referenced from within this type set @param t [PAnyType] @return [String] the name by which the type is referenced within this type set

@api private

    # File lib/puppet/pops/types/p_type_set_type.rb
231 def name_for(t, default_name)
232   key = @types.key(t)
233   if key.nil?
234     if @references.empty?
235       default_name
236     else
237       @references.each_pair do |ref_key, ref|
238         ref_name = ref.type_set.name_for(t, nil)
239         return "#{ref_key}::#{ref_name}" unless ref_name.nil?
240       end
241       default_name
242     end
243   else
244     key
245   end
246 end
resolve(loader) click to toggle source

@api private

Calls superclass method Puppet::Pops::Types::PMetaType#resolve
    # File lib/puppet/pops/types/p_type_set_type.rb
260 def resolve(loader)
261   super
262   @references.each_value { |ref| ref.resolve(loader) }
263   tsa_loader = TypeSetLoader.new(self, loader)
264   @types.values.each { |type| type.resolve(tsa_loader) }
265   self
266 end
resolve_hash(loader, init_hash) click to toggle source

@api private

    # File lib/puppet/pops/types/p_type_set_type.rb
323 def resolve_hash(loader, init_hash)
324   result = Hash[init_hash.map do |key, value|
325     key = resolve_type_refs(loader, key)
326     value = resolve_type_refs(loader, value) unless key == KEY_TYPES && value.is_a?(Hash)
327     [key, value]
328   end]
329   name_auth = resolve_name_authority(result, loader)
330   types = result[KEY_TYPES]
331   if types.is_a?(Hash)
332     types.each do |type_name, value|
333       full_name = "#{@name}::#{type_name}".freeze
334       typed_name = Loader::TypedName.new(:type, full_name, name_auth)
335       meta_name = value.is_a?(Hash) ? 'Object' : 'TypeAlias'
336       type = Loader::TypeDefinitionInstantiator.create_named_type(full_name, meta_name, value, name_auth)
337       loader.set_entry(typed_name, type)
338       types[type_name] = type
339     end
340   end
341   result
342 end
resolve_literal_hash(loader, init_hash_expression) click to toggle source

@api private

    # File lib/puppet/pops/types/p_type_set_type.rb
269 def resolve_literal_hash(loader, init_hash_expression)
270   result = {}
271   type_parser = TypeParser.singleton
272   init_hash_expression.entries.each do |entry|
273     key = type_parser.interpret_any(entry.key, loader)
274     if (key == KEY_TYPES || key == KEY_REFERENCES) && entry.value.is_a?(Model::LiteralHash)
275       # Skip type parser interpretation and convert qualified references directly to String keys.
276       hash = {}
277       entry.value.entries.each do |he|
278         kex = he.key
279         name = kex.is_a?(Model::QualifiedReference) ? kex.cased_value : type_parser.interpret_any(kex, loader)
280         hash[name] = key == KEY_TYPES ? he.value : type_parser.interpret_any(he.value, loader)
281       end
282       result[key] = hash
283     else
284       result[key] = type_parser.interpret_any(entry.value, loader)
285     end
286   end
287 
288   name_auth = resolve_name_authority(result, loader)
289 
290   types = result[KEY_TYPES]
291   if types.is_a?(Hash)
292     types.each do |type_name, value|
293       full_name = "#{@name}::#{type_name}".freeze
294       typed_name = Loader::TypedName.new(:type, full_name, name_auth)
295       if value.is_a?(Model::ResourceDefaultsExpression)
296         # This is actually a <Parent> { <key-value entries> } notation. Convert to a literal hash that contains the parent
297         n = value.type_ref
298         name = n.cased_value
299         entries = []
300         unless name == 'Object' or name == 'TypeSet'
301           if value.operations.any? { |op| op.attribute_name == KEY_PARENT }
302             case Puppet[:strict]
303             when :warning
304               IssueReporter.warning(value, Issues::DUPLICATE_KEY, :key => KEY_PARENT)
305             when :error
306               IssueReporter.error(Puppet::ParseErrorWithIssue, value, Issues::DUPLICATE_KEY, :key => KEY_PARENT)
307             end
308           end
309           entries << Model::KeyedEntry.new(n.locator, n.offset, n.length, KEY_PARENT, n)
310         end
311         value.operations.each { |op| entries << Model::KeyedEntry.new(op.locator, op.offset, op.length, op.attribute_name, op.value_expr) }
312         value = Model::LiteralHash.new(value.locator, value.offset, value.length, entries)
313       end
314       type = Loader::TypeDefinitionInstantiator.create_type(full_name, value, name_auth)
315       loader.set_entry(typed_name, type, value.locator.to_uri(value))
316       types[type_name] = type
317     end
318   end
319   result
320 end

Protected Instance Methods

_assignable?(o, guard) click to toggle source

@api_private

    # File lib/puppet/pops/types/p_type_set_type.rb
367 def _assignable?(o, guard)
368   self.class == o.class && (self == DEFAULT || eql?(o))
369 end

Private Instance Methods

resolve_name_authority(init_hash, loader) click to toggle source
    # File lib/puppet/pops/types/p_type_set_type.rb
373 def resolve_name_authority(init_hash, loader)
374   name_auth = @name_authority
375   if name_auth.nil?
376     name_auth = init_hash[KEY_NAME_AUTHORITY]
377     name_auth = loader.name_authority if name_auth.nil? && loader.is_a?(TypeSetLoader)
378     if name_auth.nil?
379       name = @name || init_hash[KEY_NAME]
380       raise ArgumentError, "No 'name_authority' is declared in TypeSet '#{name}' and it cannot be inferred"
381     end
382   end
383   name_auth
384 end