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 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
# 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
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
@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
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 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
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
# File lib/puppet/pops/types/p_type_set_type.rb 222 def defines_type?(t) 223 !@types.key(t).nil? 224 end
# 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
# File lib/puppet/pops/types/p_type_set_type.rb 344 def hash 345 @name_authority.hash ^ @name.hash ^ @version.hash 346 end
# File lib/puppet/pops/types/p_type_set_type.rb 352 def instance?(o, guard = nil) 353 o.is_a?(PTypeSetType) 354 end
@api private
# File lib/puppet/pops/types/p_type_set_type.rb 255 def label 256 "TypeSet '#{@name}'" 257 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 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
@api private
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
@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
@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
@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