class Puppet::Pops::Types::PTypeSetType
Constants
- DEFAULT
- TYPE_STRING_OR_RANGE
- TYPE_STRING_OR_VERSION
- TYPE_TYPESET_I12N
- TYPE_TYPE_REFERENCE_I12N
Attributes
Public Class Methods
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 91 def initialize(name_or_init_hash, init_hash_expression = nil, name_authority = nil) 92 @types = EMPTY_HASH 93 @references = EMPTY_HASH 94 95 if name_or_init_hash.is_a?(Hash) 96 _pcore_init_from_hash(name_or_init_hash) 97 else 98 # Creation using "type XXX = TypeSet[{}]". This means that the name is given 99 @name = TypeAsserter.assert_instance_of('TypeSet name', Pcore::TYPE_QUALIFIED_REFERENCE, name_or_init_hash) 100 @name_authority = TypeAsserter.assert_instance_of('TypeSet name_authority', Pcore::TYPE_URI, name_authority, true) 101 @init_hash_expression = init_hash_expression 102 end 103 end
# File lib/puppet/pops/types/p_type_set_type.rb 61 def self.register_ptype(loader, ir) 62 create_ptype(loader, ir, 'AnyType', '_pcore_init_hash' => TYPE_TYPESET_I12N.resolve(loader)) 63 end
Public Instance Methods
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 193 def [](qname) 194 if qname.is_a?(Loader::TypedName) 195 return nil unless qname.type == :type && qname.name_authority == @name_authority 196 qname = qname.name 197 end 198 199 type = @types[qname] || @types[@dc_to_cc_map[qname.downcase]] 200 if type.nil? && !@references.empty? 201 segments = qname.split(TypeFormatter::NAME_SEGMENT_SEPARATOR) 202 first = segments[0] 203 type_set_ref = @references[first] || @references[@dc_to_cc_map[first.downcase]] 204 if type_set_ref.nil? 205 nil 206 else 207 type_set = type_set_ref.type_set 208 case segments.size 209 when 1 210 type_set 211 when 2 212 type_set[segments[1]] 213 else 214 segments.shift 215 type_set[segments.join(TypeFormatter::NAME_SEGMENT_SEPARATOR)] 216 end 217 end 218 else 219 type 220 end 221 end
@api private
# File lib/puppet/pops/types/p_type_set_type.rb 106 def _pcore_init_from_hash(init_hash) 107 TypeAsserter.assert_instance_of('TypeSet initializer', TYPE_TYPESET_I12N, init_hash) 108 109 # Name given to the loader have higher precedence than a name declared in the type 110 @name ||= init_hash[KEY_NAME].freeze 111 @name_authority ||= init_hash[KEY_NAME_AUTHORITY].freeze 112 113 @pcore_version = PSemVerType.convert(init_hash[Pcore::KEY_PCORE_VERSION]).freeze 114 unless Pcore::PARSABLE_PCORE_VERSIONS.include?(@pcore_version) 115 raise ArgumentError, 116 "The pcore version for TypeSet '#{@name}' is not understood by this runtime. Expected range #{Pcore::PARSABLE_PCORE_VERSIONS}, got #{@pcore_version}" 117 end 118 119 @pcore_uri = init_hash[Pcore::KEY_PCORE_URI].freeze 120 @version = PSemVerType.convert(init_hash[KEY_VERSION]) 121 @types = init_hash[KEY_TYPES] || EMPTY_HASH 122 @types.freeze 123 124 # Map downcase names to their camel-cased equivalent 125 @dc_to_cc_map = {} 126 @types.keys.each { |key| @dc_to_cc_map[key.downcase] = key } 127 128 refs = init_hash[KEY_REFERENCES] 129 if refs.nil? 130 @references = EMPTY_HASH 131 else 132 ref_map = {} 133 root_map = Hash.new { |h, k| h[k] = {} } 134 refs.each do |ref_alias, ref| 135 ref = TypeSetReference.new(self, ref) 136 137 # Protect against importing the exact same name_authority/name combination twice if the version ranges intersect 138 ref_name = ref.name 139 ref_na = ref.name_authority || @name_authority 140 na_roots = root_map[ref_na] 141 142 ranges = na_roots[ref_name] 143 if ranges.nil? 144 na_roots[ref_name] = [ref.version_range] 145 else 146 unless ranges.all? { |range| (range & ref.version_range).nil? } 147 raise ArgumentError, "TypeSet '#{@name}' references TypeSet '#{ref_na}/#{ref_name}' more than once using overlapping version ranges" 148 end 149 ranges << ref.version_range 150 end 151 152 if ref_map.has_key?(ref_alias) 153 raise ArgumentError, "TypeSet '#{@name}' references a TypeSet using alias '#{ref_alias}' more than once" 154 end 155 if @types.has_key?(ref_alias) 156 raise ArgumentError, "TypeSet '#{@name}' references a TypeSet using alias '#{ref_alias}'. The alias collides with the name of a declared type" 157 end 158 ref_map[ref_alias] = ref 159 160 @dc_to_cc_map[ref_alias.downcase] = ref_alias 161 ref_map[ref_alias] = ref 162 end 163 @references = ref_map.freeze 164 end 165 @dc_to_cc_map.freeze 166 init_annotatable(init_hash) 167 end
Produce a hash suitable for the initializer @return [Hash{String => Object}] the initialization hash
@api private
# File lib/puppet/pops/types/p_type_set_type.rb 173 def _pcore_init_hash 174 result = super() 175 result[Pcore::KEY_PCORE_URI] = @pcore_uri unless @pcore_uri.nil? 176 result[Pcore::KEY_PCORE_VERSION] = @pcore_version.to_s 177 result[KEY_NAME_AUTHORITY] = @name_authority unless @name_authority.nil? 178 result[KEY_NAME] = @name 179 result[KEY_VERSION] = @version.to_s unless @version.nil? 180 result[KEY_TYPES] = @types unless @types.empty? 181 result[KEY_REFERENCES] = Hash[@references.map { |ref_alias, ref| [ref_alias, ref._pcore_init_hash] }] unless @references.empty? 182 result 183 end
Puppet::Pops::Types::PMetaType#accept
# File lib/puppet/pops/types/p_type_set_type.rb 249 def accept(visitor, guard) 250 super 251 @types.each_value { |type| type.accept(visitor, guard) } 252 @references.each_value { |ref| ref.accept(visitor, guard) } 253 end
# File lib/puppet/pops/types/p_type_set_type.rb 223 def defines_type?(t) 224 !@types.key(t).nil? 225 end
# File lib/puppet/pops/types/p_type_set_type.rb 349 def eql?(o) 350 self.class == o.class && @name_authority == o.name_authority && @name == o.name && @version == o.version 351 end
# File lib/puppet/pops/types/p_type_set_type.rb 345 def hash 346 @name_authority.hash ^ @name.hash ^ @version.hash 347 end
# File lib/puppet/pops/types/p_type_set_type.rb 353 def instance?(o, guard = nil) 354 o.is_a?(PTypeSetType) 355 end
@api private
# File lib/puppet/pops/types/p_type_set_type.rb 256 def label 257 "TypeSet '#{@name}'" 258 end
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 232 def name_for(t, default_name) 233 key = @types.key(t) 234 if key.nil? 235 if @references.empty? 236 default_name 237 else 238 @references.each_pair do |ref_key, ref| 239 ref_name = ref.type_set.name_for(t, nil) 240 return "#{ref_key}::#{ref_name}" unless ref_name.nil? 241 end 242 default_name 243 end 244 else 245 key 246 end 247 end
@api private
Puppet::Pops::Types::PMetaType#resolve
# File lib/puppet/pops/types/p_type_set_type.rb 261 def resolve(loader) 262 super 263 @references.each_value { |ref| ref.resolve(loader) } 264 tsa_loader = TypeSetLoader.new(self, loader) 265 @types.values.each { |type| type.resolve(tsa_loader) } 266 self 267 end
@api private
# File lib/puppet/pops/types/p_type_set_type.rb 324 def resolve_hash(loader, init_hash) 325 result = Hash[init_hash.map do |key, value| 326 key = resolve_type_refs(loader, key) 327 value = resolve_type_refs(loader, value) unless key == KEY_TYPES && value.is_a?(Hash) 328 [key, value] 329 end] 330 name_auth = resolve_name_authority(result, loader) 331 types = result[KEY_TYPES] 332 if types.is_a?(Hash) 333 types.each do |type_name, value| 334 full_name = "#{@name}::#{type_name}" 335 typed_name = Loader::TypedName.new(:type, full_name, name_auth) 336 meta_name = value.is_a?(Hash) ? 'Object' : 'TypeAlias' 337 type = Loader::TypeDefinitionInstantiator.create_named_type(full_name, meta_name, value, name_auth) 338 loader.set_entry(typed_name, type) 339 types[type_name] = type 340 end 341 end 342 result 343 end
@api private
# File lib/puppet/pops/types/p_type_set_type.rb 270 def resolve_literal_hash(loader, init_hash_expression) 271 result = {} 272 type_parser = TypeParser.singleton 273 init_hash_expression.entries.each do |entry| 274 key = type_parser.interpret_any(entry.key, loader) 275 if (key == KEY_TYPES || key == KEY_REFERENCES) && entry.value.is_a?(Model::LiteralHash) 276 # Skip type parser interpretation and convert qualified references directly to String keys. 277 hash = {} 278 entry.value.entries.each do |he| 279 kex = he.key 280 name = kex.is_a?(Model::QualifiedReference) ? kex.cased_value : type_parser.interpret_any(kex, loader) 281 hash[name] = key == KEY_TYPES ? he.value : type_parser.interpret_any(he.value, loader) 282 end 283 result[key] = hash 284 else 285 result[key] = type_parser.interpret_any(entry.value, loader) 286 end 287 end 288 289 name_auth = resolve_name_authority(result, loader) 290 291 types = result[KEY_TYPES] 292 if types.is_a?(Hash) 293 types.each do |type_name, value| 294 full_name = "#{@name}::#{type_name}" 295 typed_name = Loader::TypedName.new(:type, full_name, name_auth) 296 if value.is_a?(Model::ResourceDefaultsExpression) 297 # This is actually a <Parent> { <key-value entries> } notation. Convert to a literal hash that contains the parent 298 n = value.type_ref 299 name = n.cased_value 300 entries = [] 301 unless name == 'Object' or name == 'TypeSet' 302 if value.operations.any? { |op| op.attribute_name == KEY_PARENT } 303 case Puppet[:strict] 304 when :warning 305 IssueReporter.warning(value, Issues::DUPLICATE_KEY, :key => KEY_PARENT) 306 when :error 307 IssueReporter.error(Puppet::ParseErrorWithIssue, value, Issues::DUPLICATE_KEY, :key => KEY_PARENT) 308 end 309 end 310 entries << Model::KeyedEntry.new(n.locator, n.offset, n.length, KEY_PARENT, n) 311 end 312 value.operations.each { |op| entries << Model::KeyedEntry.new(op.locator, op.offset, op.length, op.attribute_name, op.value_expr) } 313 value = Model::LiteralHash.new(value.locator, value.offset, value.length, entries) 314 end 315 type = Loader::TypeDefinitionInstantiator.create_type(full_name, value, name_auth) 316 loader.set_entry(typed_name, type, value.locator.to_uri(value)) 317 types[type_name] = type 318 end 319 end 320 result 321 end
Protected Instance Methods
@api_private
# File lib/puppet/pops/types/p_type_set_type.rb 368 def _assignable?(o, guard) 369 self.class == o.class && (self == DEFAULT || eql?(o)) 370 end