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
108 def self.assignable?(t1, t2)
109   singleton.assignable?(t1,t2)
110 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
118 def self.callable?(callable, args)
119   singleton.callable?(callable, args)
120 end
generalize(o) click to toggle source

@api public

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

@api public

    # File lib/puppet/pops/types/type_calculator.rb
123 def self.infer(o)
124   singleton.infer(o)
125 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
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
infer_set(o) click to toggle source

@api public

    # File lib/puppet/pops/types/type_calculator.rb
157 def self.infer_set(o)
158   singleton.infer_set(o)
159 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
293 def self.instance?(t, o)
294   singleton.instance?(t,o)
295 end
is_kind_of_callable?(t, optional = true) click to toggle source

@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
iterable(t) click to toggle source

@api public

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

@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

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
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
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
193 def callable?(callable, args)
194   callable.is_a?(PAnyType) && callable.callable?(args)
195 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
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
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
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
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
245 def generalize(o)
246   o.is_a?(PAnyType) ? o.generalize : o
247 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
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
infer_Array(o) click to toggle source

@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
infer_Binary(o) click to toggle source

@api private

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

@api private

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

@api private

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

@api private

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

@api private

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

@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
infer_Integer(o) click to toggle source

@api private

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

@api private

    # File lib/puppet/pops/types/type_calculator.rb
515 def infer_Iterator(o)
516   PIteratorType.new(o.element_type)
517 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
505 def infer_Module(o)
506   PTypeType::new(PRuntimeType.new(:ruby, o.name))
507 end
infer_NilClass(o) click to toggle source

@api private

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

@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
infer_PAnyType(o) click to toggle source

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
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
552 def infer_PTypeType(o)
553   PTypeType.new(o)
554 end
infer_Proc(o) click to toggle source

@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
infer_PuppetProc(o) click to toggle source

@api private

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

@api private

    # File lib/puppet/pops/types/type_calculator.rb
572 def infer_Regexp(o)
573   PRegexpType.new(o)
574 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
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
infer_Sensitive(o) click to toggle source

@api private

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

@api private

    # File lib/puppet/pops/types/type_calculator.rb
557 def infer_String(o)
558   PStringType.new(o)
559 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
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
infer_Timespan(o) click to toggle source

@api private

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

@api private

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

@api private

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

@api private

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

@api private

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

@api private

    # File lib/puppet/pops/types/type_calculator.rb
684 def infer_VersionRange(o)
685   PSemVerRangeType::DEFAULT
686 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
498 def infer_and_reduce_type(enumerable)
499   reduce_type(enumerable.map {|o| infer(o) })
500 end
infer_generic(o) click to toggle source
    # File lib/puppet/pops/types/type_calculator.rb
271 def infer_generic(o)
272   generalize(infer(o))
273 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
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
infer_set_Array(o) click to toggle source
    # 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
infer_set_Hash(o) click to toggle source
    # 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
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
709 def infer_set_Object(o)
710   infer(o)
711 end
infer_set_Version(o) click to toggle source

@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
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
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
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
317 def is_pnil?(t)
318   t.nil? || t.is_a?(PUndefType)
319 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
310 def is_ptype?(t)
311   t.is_a?(PAnyType)
312 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
186 def iterable(t)
187   # Create an iterable on the type if possible
188   Iterable.on(t)
189 end
max(a,b) click to toggle source
    # File lib/puppet/pops/types/type_calculator.rb
765 def max(a,b)
766   a >=b ? a : b
767 end
min(a,b) click to toggle source
    # File lib/puppet/pops/types/type_calculator.rb
769 def min(a,b)
770   a <= b ? a : b
771 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
491 def reduce_type(enumerable)
492   enumerable.reduce(nil) {|memo, t| common_type(memo, t) }
493 end
size_as_type(collection) click to toggle source
    # 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
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
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
superclasses(c) click to toggle source

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
to_s() click to toggle source

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
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
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
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
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
unwrap_single_variant(possible_variant) click to toggle source
    # 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

common_data?(t1, t2) click to toggle source
    # 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
common_numeric?(t1, t2) click to toggle source
    # 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
common_rich_data?(t1, t2) click to toggle source
    # 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
common_scalar?(t1, t2) click to toggle source
    # 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
common_scalar_data?(t1, t2) click to toggle source
    # 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