class Puppet::Pops::Types::TypeCalculator
The TypeCalculator can answer questions about puppet types.
The Puppet type system is primarily based on sub-classing. When asking the type calculator to infer types from Ruby in general, it may not provide the wanted answer; it does not for instance take module inclusions and extensions into account. In general the type system should be unsurprising for anyone being exposed to the notion of type. The type `Data` may require a bit more explanation; this is an abstract type that includes all scalar types, as well as Array with an element type compatible with Data, and Hash with key compatible with scalar and elements compatible with Data. Expressed differently; Data is what you typically express using JSON (with the exception that the Puppet type system also includes Pattern (regular expression) as a scalar.
Inference
The `infer(o)` method infers a Puppet type for scalar Ruby objects, and for Arrays and Hashes. The inference result is instance specific for single typed collections and allows answering questions about its embedded type. It does not however preserve multiple types in a collection, and can thus not answer questions like `[1,a].infer() =~ Array[Integer, String]` since the inference computes the common type Scalar when combining Integer and String.
The `infer_generic(o)` method infers a generic Puppet type for scalar Ruby object, Arrays and Hashes. This inference result does not contain instance specific information; e.g. Array where the integer range is the generic default. Just `infer` it also combines types into a common type.
The `infer_set(o)` method works like `infer` but preserves all type information. It does not do any reduction into common types or ranges. This method of inference is best suited for answering questions about an object being an instance of a type. It correctly answers: `[1,a].infer_set() =~ Array[Integer, String]`
The `generalize!(t)` method modifies an instance specific inference result to a generic. The method mutates the given argument. Basically, this removes string instances from String, and range from Integer and Float.
Assignability
The `assignable?(t1, t2)` method answers if t2 conforms to t1. The type t2 may be an instance, in which case its type is inferred, or a type.
Instance?
The `instance?(t, o)` method answers if the given object (instance) is an instance that is assignable to the given type.
String
Creates a string representation of a type.
Creation of Type instances
Instance of the classes in the {Types type model} are used to denote a specific type. It is most convenient to use the {TypeFactory} when creating instances.
@note
In general, new instances of the wanted type should be created as they are assigned to models using containment, and a contained object can only be in one container at a time. Also, the type system may include more details in each type instance, such as if it may be nil, be empty, contain a certain count etc. Or put differently, the puppet types are not singletons.
All types support `copy` which should be used when assigning a type where it is unknown if it is bound or not to a parent type. A check can be made with `t.eContainer().nil?`
Equality and Hash
Type instances are equal in terms of Ruby eql? and `==` if they describe the same type, but they are not `equal?` if they are not the same type instance. Two types that describe the same type have identical hash - this makes them usable as hash keys.
Types and Subclasses
In general, the type calculator should be used to answer questions if a type is a subtype of another (using {#assignable?}, or {#instance?} if the question is if a given object is an instance of a given type (or is a subtype thereof). Many of the types also have a Ruby subtype relationship; e.g. PHashType and PArrayType are both subtypes of PCollectionType, and PIntegerType, PFloatType, PStringType,… are subtypes of PScalarType. Even if it is possible to answer certain questions about type by looking at the Ruby class of the types this is considered an implementation detail, and such checks should in general be performed by the type_calculator which implements the type system semantics.
The PRuntimeType
The PRuntimeType corresponds to a type in the runtime system (currently only supported runtime is 'ruby'). The type has a runtime_type_name that corresponds to a Ruby Class name. A Runtime type can be used to describe any ruby class except for the puppet types that are specialized (i.e. PRuntimeType should not be used for Integer, String, etc. since there are specialized types for those). When the type calculator deals with PRuntimeTypes and checks for assignability, it determines the “common ancestor class” of two classes. This check is made based on the superclasses of the two classes being compared. In order to perform this, the classes must be present (i.e. they are resolved from the string form in the PRuntimeType to a loaded, instantiated Ruby Class). In general this is not a problem, since the question to produce the common super type for two objects means that the classes must be present or there would have been no instances present in the first place. If however the classes are not present, the type calculator will fall back and state that the two types at least have Any in common.
@see TypeFactory for how to create instances of types @see TypeParser how to construct a type instance from a String @see Types for details about the type model
Using the Type Calculator
The type calculator can be directly used via its class methods. If doing time critical work and doing many calls to the type calculator, it is more performant to create an instance and invoke the corresponding instance methods. Note that inference is an expensive operation, rather than inferring the same thing several times, it is in general better to infer once and then copy the result if mutation to a more generic form is required.
@api public
Public Class Methods
@api public
# File lib/puppet/pops/types/type_calculator.rb 108 def self.assignable?(t1, t2) 109 singleton.assignable?(t1,t2) 110 end
Answers, does the given callable accept the arguments given in args (an array or a tuple) @param callable [PCallableType] - the callable @param args [PArrayType, PTupleType] args optionally including a lambda callable at the end @return [Boolean] true if the callable accepts the arguments
@api public
# File lib/puppet/pops/types/type_calculator.rb 118 def self.callable?(callable, args) 119 singleton.callable?(callable, args) 120 end
@api public
# File lib/puppet/pops/types/type_calculator.rb 152 def self.generalize(o) 153 singleton.generalize(o) 154 end
@api public
# File lib/puppet/pops/types/type_calculator.rb 123 def self.infer(o) 124 singleton.infer(o) 125 end
Infers a type if given object may have callable members, else returns nil. Caller must check for nil or if returned type supports members. This is a much cheaper call than doing a call to the general infer(o) method.
@api private
# File lib/puppet/pops/types/type_calculator.rb 132 def self.infer_callable_methods_t(o) 133 # If being a value that cannot have Pcore based methods callable from Puppet Language 134 if (o.is_a?(String) || 135 o.is_a?(Numeric) || 136 o.is_a?(TrueClass) || 137 o.is_a?(FalseClass) || 138 o.is_a?(Regexp) || 139 o.instance_of?(Array) || 140 o.instance_of?(Hash) || 141 Types::PUndefType::DEFAULT.instance?(o) 142 ) 143 return nil 144 end 145 # For other objects (e.g. PObjectType instances, and runtime types) full inference needed, since that will 146 # cover looking into the runtime type registry. 147 # 148 infer(o) 149 end
@api public
# File lib/puppet/pops/types/type_calculator.rb 157 def self.infer_set(o) 158 singleton.infer_set(o) 159 end
Answers 'is o an instance of type t' @api public
# File lib/puppet/pops/types/type_calculator.rb 293 def self.instance?(t, o) 294 singleton.instance?(t,o) 295 end
@api private
# File lib/puppet/pops/types/type_calculator.rb 761 def self.is_kind_of_callable?(t, optional = true) 762 t.is_a?(PAnyType) && t.kind_of_callable?(optional) 763 end
@api public
# File lib/puppet/pops/types/type_calculator.rb 162 def self.iterable(t) 163 singleton.iterable(t) 164 end
@api public
# File lib/puppet/pops/types/type_calculator.rb 168 def initialize 169 @infer_visitor = Visitor.new(nil, 'infer',0,0) 170 @extract_visitor = Visitor.new(nil, 'extract',0,0) 171 end
Public Instance Methods
Answers 'can an instance of type t2 be assigned to a variable of type t'. Does not accept nil/undef unless the type accepts it.
@api public
# File lib/puppet/pops/types/type_calculator.rb 178 def assignable?(t, t2) 179 if t.is_a?(Module) 180 t = type(t) 181 end 182 t.is_a?(PAnyType) ? t.assignable?(t2) : false 183 end
Answers, does the given callable accept the arguments given in args (an array or a tuple)
# File lib/puppet/pops/types/type_calculator.rb 193 def callable?(callable, args) 194 callable.is_a?(PAnyType) && callable.callable?(args) 195 end
Answers, 'What is the common type of t1 and t2?'
TODO: The current implementation should be optimized for performance
@api public
# File lib/puppet/pops/types/type_calculator.rb 327 def common_type(t1, t2) 328 raise ArgumentError, 'two types expected' unless (is_ptype?(t1) || is_pnil?(t1)) && (is_ptype?(t2) || is_pnil?(t2)) 329 330 # TODO: This is not right since Scalar U Undef is Any 331 # if either is nil, the common type is the other 332 if is_pnil?(t1) 333 return t2 334 elsif is_pnil?(t2) 335 return t1 336 end 337 338 # If either side is Unit, it is the other type 339 if t1.is_a?(PUnitType) 340 return t2 341 elsif t2.is_a?(PUnitType) 342 return t1 343 end 344 345 # Simple case, one is assignable to the other 346 if assignable?(t1, t2) 347 return t1 348 elsif assignable?(t2, t1) 349 return t2 350 end 351 352 # when both are arrays, return an array with common element type 353 if t1.is_a?(PArrayType) && t2.is_a?(PArrayType) 354 return PArrayType.new(common_type(t1.element_type, t2.element_type)) 355 end 356 357 # when both are hashes, return a hash with common key- and element type 358 if t1.is_a?(PHashType) && t2.is_a?(PHashType) 359 key_type = common_type(t1.key_type, t2.key_type) 360 value_type = common_type(t1.value_type, t2.value_type) 361 return PHashType.new(key_type, value_type) 362 end 363 364 # when both are host-classes, reduce to PHostClass[] (since one was not assignable to the other) 365 if t1.is_a?(PClassType) && t2.is_a?(PClassType) 366 return PClassType::DEFAULT 367 end 368 369 # when both are resources, reduce to Resource[T] or Resource[] (since one was not assignable to the other) 370 if t1.is_a?(PResourceType) && t2.is_a?(PResourceType) 371 # only Resource[] unless the type name is the same 372 return t1.type_name == t2.type_name ? PResourceType.new(t1.type_name, nil) : PResourceType::DEFAULT 373 end 374 375 # Integers have range, expand the range to the common range 376 if t1.is_a?(PIntegerType) && t2.is_a?(PIntegerType) 377 return PIntegerType.new([t1.numeric_from, t2.numeric_from].min, [t1.numeric_to, t2.numeric_to].max) 378 end 379 380 # Floats have range, expand the range to the common range 381 if t1.is_a?(PFloatType) && t2.is_a?(PFloatType) 382 return PFloatType.new([t1.numeric_from, t2.numeric_from].min, [t1.numeric_to, t2.numeric_to].max) 383 end 384 385 if t1.is_a?(PStringType) && (t2.is_a?(PStringType) || t2.is_a?(PEnumType)) 386 if(t2.is_a?(PEnumType)) 387 return t1.value.nil? ? PEnumType::DEFAULT : PEnumType.new(t2.values | [t1.value]) 388 end 389 390 if t1.size_type.nil? || t2.size_type.nil? 391 return t1.value.nil? || t2.value.nil? ? PStringType::DEFAULT : PEnumType.new([t1.value, t2.value]) 392 end 393 394 return PStringType.new(common_type(t1.size_type, t2.size_type)) 395 end 396 397 if t1.is_a?(PPatternType) && t2.is_a?(PPatternType) 398 return PPatternType.new(t1.patterns | t2.patterns) 399 end 400 401 if t1.is_a?(PEnumType) && (t2.is_a?(PStringType) || t2.is_a?(PEnumType)) 402 # The common type is one that complies with either set 403 if t2.is_a?(PEnumType) 404 return PEnumType.new(t1.values | t2.values) 405 end 406 407 return t2.value.nil? ? PEnumType::DEFAULT : PEnumType.new(t1.values | [t2.value]) 408 end 409 410 if t1.is_a?(PVariantType) && t2.is_a?(PVariantType) 411 # The common type is one that complies with either set 412 return PVariantType.maybe_create(t1.types | t2.types) 413 end 414 415 if t1.is_a?(PRegexpType) && t2.is_a?(PRegexpType) 416 # if they were identical, the general rule would return a parameterized regexp 417 # since they were not, the result is a generic regexp type 418 return PRegexpType::DEFAULT 419 end 420 421 if t1.is_a?(PCallableType) && t2.is_a?(PCallableType) 422 # They do not have the same signature, and one is not assignable to the other, 423 # what remains is the most general form of Callable 424 return PCallableType::DEFAULT 425 end 426 427 # Common abstract types, from most specific to most general 428 if common_numeric?(t1, t2) 429 return PNumericType::DEFAULT 430 end 431 432 if common_scalar_data?(t1, t2) 433 return PScalarDataType::DEFAULT 434 end 435 436 if common_scalar?(t1, t2) 437 return PScalarType::DEFAULT 438 end 439 440 if common_data?(t1,t2) 441 return TypeFactory.data 442 end 443 444 # Meta types Type[Integer] + Type[String] => Type[Data] 445 if t1.is_a?(PTypeType) && t2.is_a?(PTypeType) 446 return PTypeType.new(common_type(t1.type, t2.type)) 447 end 448 449 if common_rich_data?(t1,t2) 450 return TypeFactory.rich_data 451 end 452 453 # If both are Runtime types 454 if t1.is_a?(PRuntimeType) && t2.is_a?(PRuntimeType) 455 if t1.runtime == t2.runtime && t1.runtime_type_name == t2.runtime_type_name 456 return t1 457 end 458 # finding the common super class requires that names are resolved to class 459 # NOTE: This only supports runtime type of :ruby 460 c1 = ClassLoader.provide_from_type(t1) 461 c2 = ClassLoader.provide_from_type(t2) 462 if c1 && c2 463 c2_superclasses = superclasses(c2) 464 superclasses(c1).each do|c1_super| 465 c2_superclasses.each do |c2_super| 466 if c1_super == c2_super 467 return PRuntimeType.new(:ruby, c1_super.name) 468 end 469 end 470 end 471 end 472 end 473 474 # They better both be Any type, or the wrong thing was asked and nil is returned 475 t1.is_a?(PAnyType) && t2.is_a?(PAnyType) ? PAnyType::DEFAULT : nil 476 end
Answers if the two given types describe the same type
# File lib/puppet/pops/types/type_calculator.rb 198 def equals(left, right) 199 return false unless left.is_a?(PAnyType) && right.is_a?(PAnyType) 200 # Types compare per class only - an extra test must be made if the are mutually assignable 201 # to find all types that represent the same type of instance 202 # 203 left == right || (assignable?(right, left) && assignable?(left, right)) 204 end
Generalizes value specific types. The generalized type is returned. @api public
# File lib/puppet/pops/types/type_calculator.rb 245 def generalize(o) 246 o.is_a?(PAnyType) ? o.generalize : o 247 end
Answers 'what is the single common Puppet Type describing o', or if o is an Array or Hash, what is the single common type of the elements (or keys and elements for a Hash). @api public
# File lib/puppet/pops/types/type_calculator.rb 253 def infer(o) 254 # Optimize the most common cases into direct calls. 255 # Explicit if/elsif/else is faster than case 256 if o.is_a?(String) 257 infer_String(o) 258 elsif o.is_a?(Integer) # need subclasses for Ruby < 2.4 259 infer_Integer(o) 260 elsif o.is_a?(Array) 261 infer_Array(o) 262 elsif o.is_a?(Hash) 263 infer_Hash(o) 264 elsif o.is_a?(Evaluator::PuppetProc) 265 infer_PuppetProc(o) 266 else 267 @infer_visitor.visit_this_0(self, o) 268 end 269 end
@api private
# File lib/puppet/pops/types/type_calculator.rb 661 def infer_Array(o) 662 if o.instance_of?(Array) 663 if o.empty? 664 PArrayType::EMPTY 665 else 666 PArrayType.new(infer_and_reduce_type(o), size_as_type(o)) 667 end 668 else 669 infer_Object(o) 670 end 671 end
@api private
# File lib/puppet/pops/types/type_calculator.rb 674 def infer_Binary(o) 675 PBinaryType::DEFAULT 676 end
@api private
# File lib/puppet/pops/types/type_calculator.rb 510 def infer_Closure(o) 511 o.type 512 end
@api private
# File lib/puppet/pops/types/type_calculator.rb 640 def infer_FalseClass(o) 641 PBooleanType::FALSE 642 end
@api private
# File lib/puppet/pops/types/type_calculator.rb 562 def infer_Float(o) 563 PFloatType.new(o, o) 564 end
@api private
# File lib/puppet/pops/types/type_calculator.rb 520 def infer_Function(o) 521 o.class.dispatcher.to_type 522 end
@api private
# File lib/puppet/pops/types/type_calculator.rb 689 def infer_Hash(o) 690 if o.instance_of?(Hash) 691 if o.empty? 692 PHashType::EMPTY 693 else 694 ktype = infer_and_reduce_type(o.keys) 695 etype = infer_and_reduce_type(o.values) 696 PHashType.new(ktype, etype, size_as_type(o)) 697 end 698 else 699 infer_Object(o) 700 end 701 end
@api private
# File lib/puppet/pops/types/type_calculator.rb 567 def infer_Integer(o) 568 PIntegerType.new(o, o) 569 end
@api private
# File lib/puppet/pops/types/type_calculator.rb 515 def infer_Iterator(o) 516 PIteratorType.new(o.element_type) 517 end
The type of all modules is PTypeType @api private
# File lib/puppet/pops/types/type_calculator.rb 505 def infer_Module(o) 506 PTypeType::new(PRuntimeType.new(:ruby, o.name)) 507 end
@api private
# File lib/puppet/pops/types/type_calculator.rb 577 def infer_NilClass(o) 578 PUndefType::DEFAULT 579 end
@api private
# File lib/puppet/pops/types/type_calculator.rb 525 def infer_Object(o) 526 if o.is_a?(PuppetObject) 527 o._pcore_type 528 else 529 name = o.class.name 530 return PRuntimeType.new(:ruby, nil) if name.nil? # anonymous class that doesn't implement PuppetObject is impossible to infer 531 ir = Loaders.implementation_registry 532 type = ir.nil? ? nil : ir.type_for_module(name) 533 return PRuntimeType.new(:ruby, name) if type.nil? 534 if type.is_a?(PObjectType) && type.parameterized? 535 type = PObjectTypeExtension.create_from_instance(type, o) 536 end 537 type 538 end 539 end
The type of all types is PTypeType @api private
# File lib/puppet/pops/types/type_calculator.rb 544 def infer_PAnyType(o) 545 PTypeType.new(o) 546 end
The type of all types is PTypeType This is the metatype short circuit. @api private
# File lib/puppet/pops/types/type_calculator.rb 552 def infer_PTypeType(o) 553 PTypeType.new(o) 554 end
@api private @param o [Proc]
# File lib/puppet/pops/types/type_calculator.rb 583 def infer_Proc(o) 584 min = 0 585 max = 0 586 mapped_types = o.parameters.map do |p| 587 case p[0] 588 when :rest 589 max = :default 590 break PAnyType::DEFAULT 591 when :req 592 min += 1 593 end 594 max += 1 595 PAnyType::DEFAULT 596 end 597 param_types = Types::PTupleType.new(mapped_types, Types::PIntegerType.new(min, max)) 598 Types::PCallableType.new(param_types) 599 end
@api private
# File lib/puppet/pops/types/type_calculator.rb 602 def infer_PuppetProc(o) 603 infer_Closure(o.closure) 604 end
@api private
# File lib/puppet/pops/types/type_calculator.rb 572 def infer_Regexp(o) 573 PRegexpType.new(o) 574 end
@api private A Puppet::Parser::Resource, or Puppet::Resource
# File lib/puppet/pops/types/type_calculator.rb 652 def infer_Resource(o) 653 # Only Puppet::Resource can have a title that is a symbol :undef, a PResource cannot. 654 # A mapping must be made to empty string. A nil value will result in an error later 655 title = o.title 656 title = '' if :undef == title 657 PTypeType.new(PResourceType.new(o.type.to_s, title)) 658 end
@api private
# File lib/puppet/pops/types/type_calculator.rb 620 def infer_Sensitive(o) 621 PSensitiveType.new(infer(o.unwrap)) 622 end
@api private
# File lib/puppet/pops/types/type_calculator.rb 557 def infer_String(o) 558 PStringType.new(o) 559 end
Inference of :default as PDefaultType, and all other are Ruby @api private
# File lib/puppet/pops/types/type_calculator.rb 608 def infer_Symbol(o) 609 case o 610 when :default 611 PDefaultType::DEFAULT 612 when :undef 613 PUndefType::DEFAULT 614 else 615 infer_Object(o) 616 end 617 end
@api private
# File lib/puppet/pops/types/type_calculator.rb 625 def infer_Timespan(o) 626 PTimespanType.new(o, o) 627 end
@api private
# File lib/puppet/pops/types/type_calculator.rb 630 def infer_Timestamp(o) 631 PTimestampType.new(o, o) 632 end
@api private
# File lib/puppet/pops/types/type_calculator.rb 635 def infer_TrueClass(o) 636 PBooleanType::TRUE 637 end
@api private
# File lib/puppet/pops/types/type_calculator.rb 645 def infer_URI(o) 646 PURIType.new(o) 647 end
@api private
# File lib/puppet/pops/types/type_calculator.rb 679 def infer_Version(o) 680 PSemVerType::DEFAULT 681 end
@api private
# File lib/puppet/pops/types/type_calculator.rb 684 def infer_VersionRange(o) 685 PSemVerRangeType::DEFAULT 686 end
Reduce an enumerable of objects to a single common type @api public
# File lib/puppet/pops/types/type_calculator.rb 498 def infer_and_reduce_type(enumerable) 499 reduce_type(enumerable.map {|o| infer(o) }) 500 end
# File lib/puppet/pops/types/type_calculator.rb 271 def infer_generic(o) 272 generalize(infer(o)) 273 end
Answers 'what is the set of Puppet Types of o' @api public
# File lib/puppet/pops/types/type_calculator.rb 278 def infer_set(o) 279 if o.instance_of?(Array) 280 infer_set_Array(o) 281 elsif o.instance_of?(Hash) 282 infer_set_Hash(o) 283 elsif o.instance_of?(SemanticPuppet::Version) 284 infer_set_Version(o) 285 else 286 infer(o) 287 end 288 end
# File lib/puppet/pops/types/type_calculator.rb 713 def infer_set_Array(o) 714 if o.empty? 715 PArrayType::EMPTY 716 else 717 PTupleType.new(o.map {|x| infer_set(x) }) 718 end 719 end
# File lib/puppet/pops/types/type_calculator.rb 721 def infer_set_Hash(o) 722 if o.empty? 723 PHashType::EMPTY 724 elsif o.keys.all? {|k| PStringType::NON_EMPTY.instance?(k) } 725 PStructType.new(o.each_pair.map { |k,v| PStructElement.new(PStringType.new(k), infer_set(v)) }) 726 else 727 ktype = PVariantType.maybe_create(o.keys.map {|k| infer_set(k) }) 728 etype = PVariantType.maybe_create(o.values.map {|e| infer_set(e) }) 729 PHashType.new(unwrap_single_variant(ktype), unwrap_single_variant(etype), size_as_type(o)) 730 end 731 end
Common case for everything that intrinsically only has a single type
# File lib/puppet/pops/types/type_calculator.rb 709 def infer_set_Object(o) 710 infer(o) 711 end
@api private
# File lib/puppet/pops/types/type_calculator.rb 734 def infer_set_Version(o) 735 PSemVerType.new([SemanticPuppet::VersionRange.new(o, o)]) 736 end
Answers 'is o an instance of type t' @api public
# File lib/puppet/pops/types/type_calculator.rb 300 def instance?(t, o) 301 if t.is_a?(Module) 302 t = type(t) 303 end 304 t.is_a?(PAnyType) ? t.instance?(o) : false 305 end
Answers if t represents the puppet type PUndefType @api public
# File lib/puppet/pops/types/type_calculator.rb 317 def is_pnil?(t) 318 t.nil? || t.is_a?(PUndefType) 319 end
Answers if t is a puppet type @api public
# File lib/puppet/pops/types/type_calculator.rb 310 def is_ptype?(t) 311 t.is_a?(PAnyType) 312 end
Returns an iterable if the t represents something that can be iterated
# File lib/puppet/pops/types/type_calculator.rb 186 def iterable(t) 187 # Create an iterable on the type if possible 188 Iterable.on(t) 189 end
# File lib/puppet/pops/types/type_calculator.rb 765 def max(a,b) 766 a >=b ? a : b 767 end
# File lib/puppet/pops/types/type_calculator.rb 769 def min(a,b) 770 a <= b ? a : b 771 end
Reduces an enumerable of types to a single common type. @api public
# File lib/puppet/pops/types/type_calculator.rb 491 def reduce_type(enumerable) 492 enumerable.reduce(nil) {|memo, t| common_type(memo, t) } 493 end
# File lib/puppet/pops/types/type_calculator.rb 703 def size_as_type(collection) 704 size = collection.size 705 PIntegerType.new(size, size) 706 end
Transform int range to a size constraint if range == nil the constraint is 1,1 if range.from == nil min size = 1 if range.to == nil max size == Infinity
# File lib/puppet/pops/types/type_calculator.rb 751 def size_range(range) 752 return [1,1] if range.nil? 753 from = range.from 754 to = range.to 755 x = from.nil? ? 1 : from 756 y = to.nil? ? TheInfinity : to 757 [x, y] 758 end
Produces the superclasses of the given class, including the class
# File lib/puppet/pops/types/type_calculator.rb 479 def superclasses(c) 480 result = [c] 481 while s = c.superclass #rubocop:disable Lint/AssignmentInCondition 482 result << s 483 c = s 484 end 485 result 486 end
Debugging to_s to reduce the amount of output
# File lib/puppet/pops/types/type_calculator.rb 793 def to_s 794 '[a TypeCalculator]' 795 end
Produces the tuple entry at the given index given a tuple type, its from/to constraints on the last type, and an index. Produces nil if the index is out of bounds from must be less than to, and from may not be less than 0
@api private
# File lib/puppet/pops/types/type_calculator.rb 780 def tuple_entry_at(tuple_t, from, to, index) 781 regular = (tuple_t.types.size - 1) 782 if index < regular 783 tuple_t.types[index] 784 elsif index < regular + to 785 # in the varargs part 786 tuple_t.types[-1] 787 else 788 nil 789 end 790 end
Answers 'what is the Puppet Type corresponding to the given Ruby class' @param c [Module] the class for which a puppet type is wanted @api public
# File lib/puppet/pops/types/type_calculator.rb 210 def type(c) 211 raise ArgumentError, 'Argument must be a Module' unless c.is_a? Module 212 213 # Can't use a visitor here since we don't have an instance of the class 214 case 215 when c <= Integer 216 type = PIntegerType::DEFAULT 217 when c == Float 218 type = PFloatType::DEFAULT 219 when c == Numeric 220 type = PNumericType::DEFAULT 221 when c == String 222 type = PStringType::DEFAULT 223 when c == Regexp 224 type = PRegexpType::DEFAULT 225 when c == NilClass 226 type = PUndefType::DEFAULT 227 when c == FalseClass, c == TrueClass 228 type = PBooleanType::DEFAULT 229 when c == Class 230 type = PTypeType::DEFAULT 231 when c == Array 232 # Assume array of any 233 type = PArrayType::DEFAULT 234 when c == Hash 235 # Assume hash of any 236 type = PHashType::DEFAULT 237 else 238 type = PRuntimeType.new(:ruby, c.name) 239 end 240 type 241 end
# File lib/puppet/pops/types/type_calculator.rb 738 def unwrap_single_variant(possible_variant) 739 if possible_variant.is_a?(PVariantType) && possible_variant.types.size == 1 740 possible_variant.types[0] 741 else 742 possible_variant 743 end 744 end
Private Instance Methods
# File lib/puppet/pops/types/type_calculator.rb 804 def common_data?(t1, t2) 805 d = TypeFactory.data 806 d.assignable?(t1) && d.assignable?(t2) 807 end
# File lib/puppet/pops/types/type_calculator.rb 817 def common_numeric?(t1, t2) 818 PNumericType::DEFAULT.assignable?(t1) && PNumericType::DEFAULT.assignable?(t2) 819 end
# File lib/puppet/pops/types/type_calculator.rb 799 def common_rich_data?(t1, t2) 800 d = TypeFactory.rich_data 801 d.assignable?(t1) && d.assignable?(t2) 802 end
# File lib/puppet/pops/types/type_calculator.rb 813 def common_scalar?(t1, t2) 814 PScalarType::DEFAULT.assignable?(t1) && PScalarType::DEFAULT.assignable?(t2) 815 end
# File lib/puppet/pops/types/type_calculator.rb 809 def common_scalar_data?(t1, t2) 810 PScalarDataType::DEFAULT.assignable?(t1) && PScalarDataType::DEFAULT.assignable?(t2) 811 end