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

assignable?(t1, t2) click to toggle source

@api public

    # File lib/puppet/pops/types/type_calculator.rb
107 def self.assignable?(t1, t2)
108   singleton.assignable?(t1,t2)
109 end
callable?(callable, args) click to toggle source

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
117 def self.callable?(callable, args)
118   singleton.callable?(callable, args)
119 end
generalize(o) click to toggle source

@api public

    # File lib/puppet/pops/types/type_calculator.rb
151 def self.generalize(o)
152   singleton.generalize(o)
153 end
infer(o) click to toggle source

@api public

    # File lib/puppet/pops/types/type_calculator.rb
122 def self.infer(o)
123   singleton.infer(o)
124 end
infer_callable_methods_t(o) click to toggle source

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
131 def self.infer_callable_methods_t(o)
132   # If being a value that cannot have Pcore based methods callable from Puppet Language
133   if (o.is_a?(String) ||
134     o.is_a?(Numeric) ||
135     o.is_a?(TrueClass) ||
136     o.is_a?(FalseClass) ||
137     o.is_a?(Regexp) ||
138     o.instance_of?(Array) ||
139     o.instance_of?(Hash) ||
140     Types::PUndefType::DEFAULT.instance?(o)
141     )
142     return nil
143   end
144   # For other objects (e.g. PObjectType instances, and runtime types) full inference needed, since that will
145   # cover looking into the runtime type registry.
146   #
147   infer(o)
148 end
infer_set(o) click to toggle source

@api public

    # File lib/puppet/pops/types/type_calculator.rb
156 def self.infer_set(o)
157   singleton.infer_set(o)
158 end
instance?(t, o) click to toggle source

Answers 'is o an instance of type t' @api public

    # File lib/puppet/pops/types/type_calculator.rb
292 def self.instance?(t, o)
293   singleton.instance?(t,o)
294 end
is_kind_of_callable?(t, optional = true) click to toggle source

@api private

    # File lib/puppet/pops/types/type_calculator.rb
760 def self.is_kind_of_callable?(t, optional = true)
761   t.is_a?(PAnyType) && t.kind_of_callable?(optional)
762 end
iterable(t) click to toggle source

@api public

    # File lib/puppet/pops/types/type_calculator.rb
161 def self.iterable(t)
162   singleton.iterable(t)
163 end
new() click to toggle source

@api public

    # File lib/puppet/pops/types/type_calculator.rb
167 def initialize
168   @infer_visitor = Visitor.new(nil, 'infer',0,0)
169   @extract_visitor = Visitor.new(nil, 'extract',0,0)
170 end

Public Instance Methods

assignable?(t, t2) click to toggle source

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
177 def assignable?(t, t2)
178   if t.is_a?(Module)
179     t = type(t)
180   end
181   t.is_a?(PAnyType) ? t.assignable?(t2) : false
182 end
callable?(callable, args) click to toggle source

Answers, does the given callable accept the arguments given in args (an array or a tuple)

    # File lib/puppet/pops/types/type_calculator.rb
192 def callable?(callable, args)
193   callable.is_a?(PAnyType) && callable.callable?(args)
194 end
common_type(t1, t2) click to toggle source

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
326 def common_type(t1, t2)
327   raise ArgumentError, 'two types expected' unless (is_ptype?(t1) || is_pnil?(t1)) && (is_ptype?(t2) || is_pnil?(t2))
328 
329   # TODO: This is not right since Scalar U Undef is Any
330   # if either is nil, the common type is the other
331   if is_pnil?(t1)
332     return t2
333   elsif is_pnil?(t2)
334     return t1
335   end
336 
337   # If either side is Unit, it is the other type
338   if t1.is_a?(PUnitType)
339     return t2
340   elsif t2.is_a?(PUnitType)
341     return t1
342   end
343 
344   # Simple case, one is assignable to the other
345   if assignable?(t1, t2)
346     return t1
347   elsif assignable?(t2, t1)
348     return t2
349   end
350 
351   # when both are arrays, return an array with common element type
352   if t1.is_a?(PArrayType) && t2.is_a?(PArrayType)
353     return PArrayType.new(common_type(t1.element_type, t2.element_type))
354   end
355 
356   # when both are hashes, return a hash with common key- and element type
357   if t1.is_a?(PHashType) && t2.is_a?(PHashType)
358     key_type = common_type(t1.key_type, t2.key_type)
359     value_type = common_type(t1.value_type, t2.value_type)
360     return PHashType.new(key_type, value_type)
361   end
362 
363   # when both are host-classes, reduce to PHostClass[] (since one was not assignable to the other)
364   if t1.is_a?(PClassType) && t2.is_a?(PClassType)
365     return PClassType::DEFAULT
366   end
367 
368   # when both are resources, reduce to Resource[T] or Resource[] (since one was not assignable to the other)
369   if t1.is_a?(PResourceType) && t2.is_a?(PResourceType)
370     # only Resource[] unless the type name is the same
371     return t1.type_name == t2.type_name ?  PResourceType.new(t1.type_name, nil) : PResourceType::DEFAULT
372   end
373 
374   # Integers have range, expand the range to the common range
375   if t1.is_a?(PIntegerType) && t2.is_a?(PIntegerType)
376     return PIntegerType.new([t1.numeric_from, t2.numeric_from].min, [t1.numeric_to, t2.numeric_to].max)
377   end
378 
379   # Floats have range, expand the range to the common range
380   if t1.is_a?(PFloatType) && t2.is_a?(PFloatType)
381     return PFloatType.new([t1.numeric_from, t2.numeric_from].min, [t1.numeric_to, t2.numeric_to].max)
382   end
383 
384   if t1.is_a?(PStringType) && (t2.is_a?(PStringType) || t2.is_a?(PEnumType))
385     if(t2.is_a?(PEnumType))
386       return t1.value.nil? ? PEnumType::DEFAULT : PEnumType.new(t2.values | [t1.value])
387     end
388 
389     if t1.size_type.nil? || t2.size_type.nil?
390       return t1.value.nil? || t2.value.nil? ? PStringType::DEFAULT : PEnumType.new([t1.value, t2.value])
391     end
392 
393     return PStringType.new(common_type(t1.size_type, t2.size_type))
394   end
395 
396   if t1.is_a?(PPatternType) && t2.is_a?(PPatternType)
397     return PPatternType.new(t1.patterns | t2.patterns)
398   end
399 
400   if t1.is_a?(PEnumType) && (t2.is_a?(PStringType) || t2.is_a?(PEnumType))
401     # The common type is one that complies with either set
402     if t2.is_a?(PEnumType)
403       return PEnumType.new(t1.values | t2.values)
404     end
405 
406     return t2.value.nil? ? PEnumType::DEFAULT : PEnumType.new(t1.values | [t2.value])
407   end
408 
409   if t1.is_a?(PVariantType) && t2.is_a?(PVariantType)
410     # The common type is one that complies with either set
411     return PVariantType.maybe_create(t1.types | t2.types)
412   end
413 
414   if t1.is_a?(PRegexpType) && t2.is_a?(PRegexpType)
415     # if they were identical, the general rule would return a parameterized regexp
416     # since they were not, the result is a generic regexp type
417     return PRegexpType::DEFAULT
418   end
419 
420   if t1.is_a?(PCallableType) && t2.is_a?(PCallableType)
421     # They do not have the same signature, and one is not assignable to the other,
422     # what remains is the most general form of Callable
423     return PCallableType::DEFAULT
424   end
425 
426   # Common abstract types, from most specific to most general
427   if common_numeric?(t1, t2)
428     return PNumericType::DEFAULT
429   end
430 
431   if common_scalar_data?(t1, t2)
432     return PScalarDataType::DEFAULT
433   end
434 
435   if common_scalar?(t1, t2)
436     return PScalarType::DEFAULT
437   end
438 
439   if common_data?(t1,t2)
440     return TypeFactory.data
441   end
442 
443   # Meta types Type[Integer] + Type[String] => Type[Data]
444   if t1.is_a?(PTypeType) && t2.is_a?(PTypeType)
445     return PTypeType.new(common_type(t1.type, t2.type))
446   end
447 
448   if common_rich_data?(t1,t2)
449     return TypeFactory.rich_data
450   end
451 
452   # If both are Runtime types
453   if t1.is_a?(PRuntimeType) && t2.is_a?(PRuntimeType)
454     if t1.runtime == t2.runtime && t1.runtime_type_name == t2.runtime_type_name
455       return t1
456     end
457     # finding the common super class requires that names are resolved to class
458     # NOTE: This only supports runtime type of :ruby
459     c1 = ClassLoader.provide_from_type(t1)
460     c2 = ClassLoader.provide_from_type(t2)
461     if c1 && c2
462       c2_superclasses = superclasses(c2)
463       superclasses(c1).each do|c1_super|
464         c2_superclasses.each do |c2_super|
465           if c1_super == c2_super
466             return PRuntimeType.new(:ruby, c1_super.name)
467           end
468         end
469       end
470     end
471   end
472 
473   # They better both be Any type, or the wrong thing was asked and nil is returned
474   t1.is_a?(PAnyType) && t2.is_a?(PAnyType) ? PAnyType::DEFAULT : nil
475 end
equals(left, right) click to toggle source

Answers if the two given types describe the same type

    # File lib/puppet/pops/types/type_calculator.rb
197 def equals(left, right)
198   return false unless left.is_a?(PAnyType) && right.is_a?(PAnyType)
199   # Types compare per class only - an extra test must be made if the are mutually assignable
200   # to find all types that represent the same type of instance
201   #
202   left == right || (assignable?(right, left) && assignable?(left, right))
203 end
generalize(o) click to toggle source

Generalizes value specific types. The generalized type is returned. @api public

    # File lib/puppet/pops/types/type_calculator.rb
244 def generalize(o)
245   o.is_a?(PAnyType) ? o.generalize : o
246 end
infer(o) click to toggle source

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
252 def infer(o)
253   # Optimize the most common cases into direct calls.
254   # Explicit if/elsif/else is faster than case
255   if o.is_a?(String)
256     infer_String(o)
257   elsif o.is_a?(Integer) # need subclasses for Ruby < 2.4
258     infer_Integer(o)
259   elsif o.is_a?(Array)
260     infer_Array(o)
261   elsif o.is_a?(Hash)
262     infer_Hash(o)
263   elsif o.is_a?(Evaluator::PuppetProc)
264     infer_PuppetProc(o)
265   else
266     @infer_visitor.visit_this_0(self, o)
267   end
268 end
infer_Array(o) click to toggle source

@api private

    # File lib/puppet/pops/types/type_calculator.rb
660 def infer_Array(o)
661   if o.instance_of?(Array)
662     if o.empty?
663       PArrayType::EMPTY
664     else
665       PArrayType.new(infer_and_reduce_type(o), size_as_type(o))
666     end
667   else
668     infer_Object(o)
669   end
670 end
infer_Binary(o) click to toggle source

@api private

    # File lib/puppet/pops/types/type_calculator.rb
673 def infer_Binary(o)
674   PBinaryType::DEFAULT
675 end
infer_Closure(o) click to toggle source

@api private

    # File lib/puppet/pops/types/type_calculator.rb
509 def infer_Closure(o)
510   o.type
511 end
infer_FalseClass(o) click to toggle source

@api private

    # File lib/puppet/pops/types/type_calculator.rb
639 def infer_FalseClass(o)
640   PBooleanType::FALSE
641 end
infer_Float(o) click to toggle source

@api private

    # File lib/puppet/pops/types/type_calculator.rb
561 def infer_Float(o)
562   PFloatType.new(o, o)
563 end
infer_Function(o) click to toggle source

@api private

    # File lib/puppet/pops/types/type_calculator.rb
519 def infer_Function(o)
520   o.class.dispatcher.to_type
521 end
infer_Hash(o) click to toggle source

@api private

    # File lib/puppet/pops/types/type_calculator.rb
688 def infer_Hash(o)
689   if o.instance_of?(Hash)
690     if o.empty?
691       PHashType::EMPTY
692     else
693       ktype = infer_and_reduce_type(o.keys)
694       etype = infer_and_reduce_type(o.values)
695       PHashType.new(ktype, etype, size_as_type(o))
696     end
697   else
698     infer_Object(o)
699   end
700 end
infer_Integer(o) click to toggle source

@api private

    # File lib/puppet/pops/types/type_calculator.rb
566 def infer_Integer(o)
567   PIntegerType.new(o, o)
568 end
infer_Iterator(o) click to toggle source

@api private

    # File lib/puppet/pops/types/type_calculator.rb
514 def infer_Iterator(o)
515   PIteratorType.new(o.element_type)
516 end
infer_Module(o) click to toggle source

The type of all modules is PTypeType @api private

    # File lib/puppet/pops/types/type_calculator.rb
504 def infer_Module(o)
505   PTypeType::new(PRuntimeType.new(:ruby, o.name))
506 end
infer_NilClass(o) click to toggle source

@api private

    # File lib/puppet/pops/types/type_calculator.rb
576 def infer_NilClass(o)
577   PUndefType::DEFAULT
578 end
infer_Object(o) click to toggle source

@api private

    # File lib/puppet/pops/types/type_calculator.rb
524 def infer_Object(o)
525   if o.is_a?(PuppetObject)
526     o._pcore_type
527   else
528     name = o.class.name
529     return PRuntimeType.new(:ruby, nil) if name.nil? # anonymous class that doesn't implement PuppetObject is impossible to infer
530     ir = Loaders.implementation_registry
531     type = ir.nil? ? nil : ir.type_for_module(name)
532     return PRuntimeType.new(:ruby, name) if type.nil?
533     if type.is_a?(PObjectType) && type.parameterized?
534       type = PObjectTypeExtension.create_from_instance(type, o)
535     end
536     type
537   end
538 end
infer_PAnyType(o) click to toggle source

The type of all types is PTypeType @api private

    # File lib/puppet/pops/types/type_calculator.rb
543 def infer_PAnyType(o)
544   PTypeType.new(o)
545 end
infer_PTypeType(o) click to toggle source

The type of all types is PTypeType This is the metatype short circuit. @api private

    # File lib/puppet/pops/types/type_calculator.rb
551 def infer_PTypeType(o)
552   PTypeType.new(o)
553 end
infer_Proc(o) click to toggle source

@api private @param o [Proc]

    # File lib/puppet/pops/types/type_calculator.rb
582 def infer_Proc(o)
583   min = 0
584   max = 0
585   mapped_types = o.parameters.map do |p|
586     case p[0]
587     when :rest
588       max = :default
589       break PAnyType::DEFAULT
590     when :req
591       min += 1
592     end
593     max += 1
594     PAnyType::DEFAULT
595   end
596   param_types = Types::PTupleType.new(mapped_types, Types::PIntegerType.new(min, max))
597   Types::PCallableType.new(param_types)
598 end
infer_PuppetProc(o) click to toggle source

@api private

    # File lib/puppet/pops/types/type_calculator.rb
601 def infer_PuppetProc(o)
602   infer_Closure(o.closure)
603 end
infer_Regexp(o) click to toggle source

@api private

    # File lib/puppet/pops/types/type_calculator.rb
571 def infer_Regexp(o)
572   PRegexpType.new(o)
573 end
infer_Resource(o) click to toggle source

@api private A Puppet::Parser::Resource, or Puppet::Resource

    # File lib/puppet/pops/types/type_calculator.rb
651 def infer_Resource(o)
652   # Only Puppet::Resource can have a title that is a symbol :undef, a PResource cannot.
653   # A mapping must be made to empty string. A nil value will result in an error later
654   title = o.title
655   title = '' if :undef == title
656   PTypeType.new(PResourceType.new(o.type.to_s, title))
657 end
infer_Sensitive(o) click to toggle source

@api private

    # File lib/puppet/pops/types/type_calculator.rb
619 def infer_Sensitive(o)
620   PSensitiveType.new(infer(o.unwrap))
621 end
infer_String(o) click to toggle source

@api private

    # File lib/puppet/pops/types/type_calculator.rb
556 def infer_String(o)
557   PStringType.new(o)
558 end
infer_Symbol(o) click to toggle source

Inference of :default as PDefaultType, and all other are Ruby @api private

    # File lib/puppet/pops/types/type_calculator.rb
607 def infer_Symbol(o)
608   case o
609   when :default
610     PDefaultType::DEFAULT
611   when :undef
612     PUndefType::DEFAULT
613   else
614     infer_Object(o)
615   end
616 end
infer_Timespan(o) click to toggle source

@api private

    # File lib/puppet/pops/types/type_calculator.rb
624 def infer_Timespan(o)
625   PTimespanType.new(o, o)
626 end
infer_Timestamp(o) click to toggle source

@api private

    # File lib/puppet/pops/types/type_calculator.rb
629 def infer_Timestamp(o)
630   PTimestampType.new(o, o)
631 end
infer_TrueClass(o) click to toggle source

@api private

    # File lib/puppet/pops/types/type_calculator.rb
634 def infer_TrueClass(o)
635   PBooleanType::TRUE
636 end
infer_URI(o) click to toggle source

@api private

    # File lib/puppet/pops/types/type_calculator.rb
644 def infer_URI(o)
645   PURIType.new(o)
646 end
infer_Version(o) click to toggle source

@api private

    # File lib/puppet/pops/types/type_calculator.rb
678 def infer_Version(o)
679   PSemVerType::DEFAULT
680 end
infer_VersionRange(o) click to toggle source

@api private

    # File lib/puppet/pops/types/type_calculator.rb
683 def infer_VersionRange(o)
684   PSemVerRangeType::DEFAULT
685 end
infer_and_reduce_type(enumerable) click to toggle source

Reduce an enumerable of objects to a single common type @api public

    # File lib/puppet/pops/types/type_calculator.rb
497 def infer_and_reduce_type(enumerable)
498   reduce_type(enumerable.map {|o| infer(o) })
499 end
infer_generic(o) click to toggle source
    # File lib/puppet/pops/types/type_calculator.rb
270 def infer_generic(o)
271   generalize(infer(o))
272 end
infer_set(o) click to toggle source

Answers 'what is the set of Puppet Types of o' @api public

    # File lib/puppet/pops/types/type_calculator.rb
277 def infer_set(o)
278   if o.instance_of?(Array)
279     infer_set_Array(o)
280   elsif o.instance_of?(Hash)
281     infer_set_Hash(o)
282   elsif o.instance_of?(SemanticPuppet::Version)
283     infer_set_Version(o)
284   else
285     infer(o)
286   end
287 end
infer_set_Array(o) click to toggle source
    # File lib/puppet/pops/types/type_calculator.rb
712 def infer_set_Array(o)
713   if o.empty?
714     PArrayType::EMPTY
715   else
716     PTupleType.new(o.map {|x| infer_set(x) })
717   end
718 end
infer_set_Hash(o) click to toggle source
    # File lib/puppet/pops/types/type_calculator.rb
720 def infer_set_Hash(o)
721   if o.empty?
722     PHashType::EMPTY
723   elsif o.keys.all? {|k| PStringType::NON_EMPTY.instance?(k) }
724     PStructType.new(o.each_pair.map { |k,v| PStructElement.new(PStringType.new(k), infer_set(v)) })
725   else
726     ktype = PVariantType.maybe_create(o.keys.map {|k| infer_set(k) })
727     etype = PVariantType.maybe_create(o.values.map {|e| infer_set(e) })
728     PHashType.new(unwrap_single_variant(ktype), unwrap_single_variant(etype), size_as_type(o))
729   end
730 end
infer_set_Object(o) click to toggle source

Common case for everything that intrinsically only has a single type

    # File lib/puppet/pops/types/type_calculator.rb
708 def infer_set_Object(o)
709   infer(o)
710 end
infer_set_Version(o) click to toggle source

@api private

    # File lib/puppet/pops/types/type_calculator.rb
733 def infer_set_Version(o)
734   PSemVerType.new([SemanticPuppet::VersionRange.new(o, o)])
735 end
instance?(t, o) click to toggle source

Answers 'is o an instance of type t' @api public

    # File lib/puppet/pops/types/type_calculator.rb
299 def instance?(t, o)
300   if t.is_a?(Module)
301     t = type(t)
302   end
303   t.is_a?(PAnyType) ? t.instance?(o) : false
304 end
is_pnil?(t) click to toggle source

Answers if t represents the puppet type PUndefType @api public

    # File lib/puppet/pops/types/type_calculator.rb
316 def is_pnil?(t)
317   t.nil? || t.is_a?(PUndefType)
318 end
is_ptype?(t) click to toggle source

Answers if t is a puppet type @api public

    # File lib/puppet/pops/types/type_calculator.rb
309 def is_ptype?(t)
310   t.is_a?(PAnyType)
311 end
iterable(t) click to toggle source

Returns an iterable if the t represents something that can be iterated

    # File lib/puppet/pops/types/type_calculator.rb
185 def iterable(t)
186   # Create an iterable on the type if possible
187   Iterable.on(t)
188 end
max(a,b) click to toggle source
    # File lib/puppet/pops/types/type_calculator.rb
764 def max(a,b)
765   a >=b ? a : b
766 end
min(a,b) click to toggle source
    # File lib/puppet/pops/types/type_calculator.rb
768 def min(a,b)
769   a <= b ? a : b
770 end
reduce_type(enumerable) click to toggle source

Reduces an enumerable of types to a single common type. @api public

    # File lib/puppet/pops/types/type_calculator.rb
490 def reduce_type(enumerable)
491   enumerable.reduce(nil) {|memo, t| common_type(memo, t) }
492 end
size_as_type(collection) click to toggle source
    # File lib/puppet/pops/types/type_calculator.rb
702 def size_as_type(collection)
703   size = collection.size
704   PIntegerType.new(size, size)
705 end
size_range(range) click to toggle source

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
750 def size_range(range)
751   return [1,1] if range.nil?
752   from = range.from
753   to = range.to
754   x = from.nil? ? 1 : from
755   y = to.nil? ? TheInfinity : to
756   [x, y]
757 end
superclasses(c) click to toggle source

Produces the superclasses of the given class, including the class

    # File lib/puppet/pops/types/type_calculator.rb
478 def superclasses(c)
479   result = [c]
480   while s = c.superclass #rubocop:disable Lint/AssignmentInCondition
481     result << s
482     c = s
483   end
484   result
485 end
to_s() click to toggle source

Debugging to_s to reduce the amount of output

    # File lib/puppet/pops/types/type_calculator.rb
792 def to_s
793   '[a TypeCalculator]'
794 end
tuple_entry_at(tuple_t, from, to, index) click to toggle source

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
779 def tuple_entry_at(tuple_t, from, to, index)
780   regular = (tuple_t.types.size - 1)
781   if index < regular
782     tuple_t.types[index]
783   elsif index < regular + to
784     # in the varargs part
785     tuple_t.types[-1]
786   else
787     nil
788   end
789 end
type(c) click to toggle source

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
209 def type(c)
210   raise ArgumentError, 'Argument must be a Module' unless c.is_a? Module
211 
212   # Can't use a visitor here since we don't have an instance of the class
213   case
214   when c <= Integer
215     type = PIntegerType::DEFAULT
216   when c == Float
217     type = PFloatType::DEFAULT
218   when c == Numeric
219     type = PNumericType::DEFAULT
220   when c == String
221     type = PStringType::DEFAULT
222   when c == Regexp
223     type = PRegexpType::DEFAULT
224   when c == NilClass
225     type = PUndefType::DEFAULT
226   when c == FalseClass, c == TrueClass
227     type = PBooleanType::DEFAULT
228   when c == Class
229     type = PTypeType::DEFAULT
230   when c == Array
231     # Assume array of any
232     type = PArrayType::DEFAULT
233   when c == Hash
234     # Assume hash of any
235     type = PHashType::DEFAULT
236  else
237     type = PRuntimeType.new(:ruby, c.name)
238   end
239   type
240 end
unwrap_single_variant(possible_variant) click to toggle source
    # File lib/puppet/pops/types/type_calculator.rb
737 def unwrap_single_variant(possible_variant)
738   if possible_variant.is_a?(PVariantType) && possible_variant.types.size == 1
739     possible_variant.types[0]
740   else
741     possible_variant
742   end
743 end

Private Instance Methods

common_data?(t1, t2) click to toggle source
    # File lib/puppet/pops/types/type_calculator.rb
803 def common_data?(t1, t2)
804   d = TypeFactory.data
805   d.assignable?(t1) && d.assignable?(t2)
806 end
common_numeric?(t1, t2) click to toggle source
    # File lib/puppet/pops/types/type_calculator.rb
816 def common_numeric?(t1, t2)
817   PNumericType::DEFAULT.assignable?(t1) && PNumericType::DEFAULT.assignable?(t2)
818 end
common_rich_data?(t1, t2) click to toggle source
    # File lib/puppet/pops/types/type_calculator.rb
798 def common_rich_data?(t1, t2)
799   d = TypeFactory.rich_data
800   d.assignable?(t1) && d.assignable?(t2)
801 end
common_scalar?(t1, t2) click to toggle source
    # File lib/puppet/pops/types/type_calculator.rb
812 def common_scalar?(t1, t2)
813   PScalarType::DEFAULT.assignable?(t1) && PScalarType::DEFAULT.assignable?(t2)
814 end
common_scalar_data?(t1, t2) click to toggle source
    # File lib/puppet/pops/types/type_calculator.rb
808 def common_scalar_data?(t1, t2)
809   PScalarDataType::DEFAULT.assignable?(t1) && PScalarDataType::DEFAULT.assignable?(t2)
810 end