Class: Puppet::Pops::Types::TypeCalculator

Inherits:
Object
  • Object
show all
Defined in:
lib/puppet/pops/types/type_calculator.rb

Overview

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.

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 type model are used to denote a specific type. It is most convenient to use the TypeFactory when creating instances.

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.

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.

Constant Summary collapse

Types =
Puppet::Pops::Types
TheInfinity =

because the Infinity symbol is not defined

1.0 / 0.0

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeTypeCalculator

Returns a new instance of TypeCalculator.



161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
# File 'lib/puppet/pops/types/type_calculator.rb', line 161

def initialize
  @@assignable_visitor ||= Puppet::Pops::Visitor.new(nil,"assignable",1,1)
  @@infer_visitor ||= Puppet::Pops::Visitor.new(nil,"infer",0,0)
  @@infer_set_visitor ||= Puppet::Pops::Visitor.new(nil,"infer_set",0,0)
  @@instance_of_visitor ||= Puppet::Pops::Visitor.new(nil,"instance_of",1,1)
  @@string_visitor ||= Puppet::Pops::Visitor.new(nil,"string",0,0)
  @@inspect_visitor ||= Puppet::Pops::Visitor.new(nil,"debug_string",0,0)
  @@enumerable_visitor ||= Puppet::Pops::Visitor.new(nil,"enumerable",0,0)
  @@extract_visitor ||= Puppet::Pops::Visitor.new(nil,"extract",0,0)
  @@generalize_visitor ||= Puppet::Pops::Visitor.new(nil,"generalize",0,0)
  @@callable_visitor ||= Puppet::Pops::Visitor.new(nil,"callable",1,1)

  da = Types::PArrayType.new()
  da.element_type = Types::PDataType.new()
  @data_array = da

  h = Types::PHashType.new()
  h.element_type = Types::PDataType.new()
  h.key_type = Types::PScalarType.new()
  @data_hash = h

  @data_t = Types::PDataType.new()
  @scalar_t = Types::PScalarType.new()
  @numeric_t = Types::PNumericType.new()
  @t = Types::PAnyType.new()

  # Data accepts a Tuple that has 0-infinity Data compatible entries (e.g. a Tuple equivalent to Array).
  data_tuple = Types::PTupleType.new()
  data_tuple.addTypes(Types::PDataType.new())
  data_tuple.size_type = Types::PIntegerType.new()
  data_tuple.size_type.from = 0
  data_tuple.size_type.to = nil # infinity
  @data_tuple_t = data_tuple

  # Variant type compatible with Data
  data_variant = Types::PVariantType.new()
  data_variant.addTypes(@data_hash.copy)
  data_variant.addTypes(@data_array.copy)
  data_variant.addTypes(Types::PScalarType.new)
  data_variant.addTypes(Types::PUndefType.new)
  data_variant.addTypes(@data_tuple_t.copy)
  @data_variant_t = data_variant

  collection_default_size = Types::PIntegerType.new()
  collection_default_size.from = 0
  collection_default_size.to = nil # infinity
  @collection_default_size_t = collection_default_size

  non_empty_string = Types::PStringType.new
  non_empty_string.size_type = Types::PIntegerType.new()
  non_empty_string.size_type.from = 1
  non_empty_string.size_type.to = nil # infinity
  @non_empty_string_t = non_empty_string

  @nil_t = Types::PUndefType.new
end

Class Method Details

.assignable?(t1, t2) ⇒ Boolean

Returns:

  • (Boolean)


105
106
107
# File 'lib/puppet/pops/types/type_calculator.rb', line 105

def self.assignable?(t1, t2)
  singleton.assignable?(t1,t2)
end

.callable?(callable, args) ⇒ Boolan

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

Parameters:

Returns:

  • (Boolan)

    true if the callable accepts the arguments



115
116
117
# File 'lib/puppet/pops/types/type_calculator.rb', line 115

def self.callable?(callable, args)
  singleton.callable?(callable, args)
end

.copy_as_tuple(t) ⇒ Object



1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
# File 'lib/puppet/pops/types/type_calculator.rb', line 1837

def self.copy_as_tuple(t)
  case t
  when Types::PTupleType
    t.copy
  when Types::PArrayType
    # transform array to tuple
    result = Types::PTupleType.new
    result.addTypes(t.element_type.copy)
    result.size_type = t.size_type.nil? ? nil : t.size_type.copy
    result
  else
    raise ArgumentError, "Internal Error: Only Array and Tuple can be given to copy_as_tuple"
  end
end

.data_variantObject



232
233
234
# File 'lib/puppet/pops/types/type_calculator.rb', line 232

def self.data_variant
  singleton.data_variant
end

.debug_string(t) ⇒ Object



145
146
147
# File 'lib/puppet/pops/types/type_calculator.rb', line 145

def self.debug_string(t)
  singleton.debug_string(t)
end

.enumerable(t) ⇒ Object



150
151
152
# File 'lib/puppet/pops/types/type_calculator.rb', line 150

def self.enumerable(t)
  singleton.enumerable(t)
end

.generalize!(o) ⇒ Object



135
136
137
# File 'lib/puppet/pops/types/type_calculator.rb', line 135

def self.generalize!(o)
  singleton.generalize!(o)
end

.infer(o) ⇒ Object



130
131
132
# File 'lib/puppet/pops/types/type_calculator.rb', line 130

def self.infer(o)
  singleton.infer(o)
end

.infer_set(o) ⇒ Object



140
141
142
# File 'lib/puppet/pops/types/type_calculator.rb', line 140

def self.infer_set(o)
  singleton.infer_set(o)
end

.instance?(t, o) ⇒ Boolean

Answers ‘is o an instance of type t’

Returns:

  • (Boolean)


528
529
530
# File 'lib/puppet/pops/types/type_calculator.rb', line 528

def self.instance?(t, o)
  singleton.instance_of(t,o)
end

.is_kind_of_callable?(t, optional = true) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (Boolean)


1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
# File 'lib/puppet/pops/types/type_calculator.rb', line 1140

def self.is_kind_of_callable?(t, optional = true)
  case t
  when Types::PCallableType
    true
  when Types::POptionalType
    optional && is_kind_of_callable?(t.optional_type, optional)
  when Types::PVariantType
    t.types.all? {|t2| is_kind_of_callable?(t2, optional) }
  else
    false
  end
end

.is_kind_of_optional?(t, optional = true) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (Boolean)


1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
# File 'lib/puppet/pops/types/type_calculator.rb', line 1154

def self.is_kind_of_optional?(t, optional = true)
  case t
  when Types::POptionalType
    true
  when Types::PVariantType
    t.types.all? {|t2| is_kind_of_optional?(t2, optional) }
  else
    false
  end
end

.singletonObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



155
156
157
# File 'lib/puppet/pops/types/type_calculator.rb', line 155

def self.singleton()
  @tc_instance ||= new
end

.string(t) ⇒ String

Produces a String representation of the given type.

Parameters:

Returns:

  • (String)

    the type in string form



125
126
127
# File 'lib/puppet/pops/types/type_calculator.rb', line 125

def self.string(t)
  singleton.string(t)
end

Instance Method Details

#assignable?(t, t2) ⇒ Boolean

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.

Returns:

  • (Boolean)


264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
# File 'lib/puppet/pops/types/type_calculator.rb', line 264

def assignable?(t, t2)
   if t.is_a?(Class)
     t = type(t)
   end

   if t2.is_a?(Class)
     t2 = type(t2)
   end
   t2_class = t2.class

   # Unit can be assigned to anything
   return true if t2_class == Types::PUnitType

   if t2_class == Types::PVariantType
     # Assignable if all contained types are assignable
     t2.types.all? { |vt| @@assignable_visitor.visit_this_1(self, t, vt) }
   else
     # Turn NotUndef[T] into T when T is not assignable from Undef
     if t2_class == Types::PNotUndefType && !(t2.type.nil? || assignable?(t2.type, @nil_t))
       assignable?(t, t2.type)
     else
       @@assignable_visitor.visit_this_1(self, t, t2)
     end
   end
end

#assignable_Object(t, t2) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

False in general type calculator



1010
1011
1012
# File 'lib/puppet/pops/types/type_calculator.rb', line 1010

def assignable_Object(t, t2)
  false
end

#assignable_PAnyType(t, t2) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1015
1016
1017
# File 'lib/puppet/pops/types/type_calculator.rb', line 1015

def assignable_PAnyType(t, t2)
  t2.is_a?(Types::PAnyType)
end

#assignable_PArrayType(t, t2) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Array is assignable if t2 is an Array and t2’s element type is assignable, or if t2 is a Tuple where



1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
# File 'lib/puppet/pops/types/type_calculator.rb', line 1454

def assignable_PArrayType(t, t2)
  if t2.is_a?(Types::PArrayType)
    return false unless t.element_type.nil? || assignable?(t.element_type, t2.element_type || @t)
    assignable_PCollectionType(t, t2)

  elsif t2.is_a?(Types::PTupleType)
    return false unless t.element_type.nil? || t2.types.all? {|t2_element| assignable?(t.element_type, t2_element) }
    t2_regular = t2.types[0..-2]
    t2_ranged = t2.types[-1]
    t2_from, t2_to = size_range(t2.size_type)
    t2_required = t2_regular.size + t2_from

    t_entry = t.element_type

    # Tuple of anything can not be assigned (unless array is tuple of anything) - this case
    # was handled at the top of this method.
    #
    return false if t_entry.nil?

    # array type may be size constrained
    size_t = t.size_type || @collection_default_size_t
    min, max = size_t.range
    # Tuple with fewer min entries can not be assigned
    return false if t2_required < min
    # Tuple with more optionally available entries can not be assigned
    return false if t2_regular.size + t2_to > max
    # each tuple type must be assignable to the element type
    t2_required.times do |index|
      t2_entry = tuple_entry_at(t2, t2_from, t2_to, index)
      return false unless assignable?(t_entry, t2_entry)
    end
    # ... and so must the last, possibly optional (ranged) type
    return assignable?(t_entry, t2_ranged)
  else
    false
  end
end

#assignable_PBooleanType(t, t2) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1392
1393
1394
# File 'lib/puppet/pops/types/type_calculator.rb', line 1392

def assignable_PBooleanType(t, t2)
  t2.is_a?(Types::PBooleanType)
end

#assignable_PCallableType(t, t2) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
# File 'lib/puppet/pops/types/type_calculator.rb', line 1402

def assignable_PCallableType(t, t2)
  return false unless t2.is_a?(Types::PCallableType)
  # nil param_types means, any other Callable is assignable
  return true if t.param_types.nil?

  # NOTE: these tests are made in reverse as it is calling the callable that is constrained
  # (it's lower bound), not its upper bound
  return false unless assignable?(t2.param_types, t.param_types)
  # names are ignored, they are just information
  # Blocks must be compatible
  this_block_t = t.block_type || @nil_t
  that_block_t = t2.block_type || @nil_t
  assignable?(that_block_t, this_block_t)

end

#assignable_PCatalogEntryType(t1, t2) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1518
1519
1520
# File 'lib/puppet/pops/types/type_calculator.rb', line 1518

def assignable_PCatalogEntryType(t1, t2)
  t2.is_a?(Types::PCatalogEntryType)
end

#assignable_PCollectionType(t, t2) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
# File 'lib/puppet/pops/types/type_calculator.rb', line 1419

def assignable_PCollectionType(t, t2)
  size_t = t.size_type || @collection_default_size_t
  case t2
  when Types::PCollectionType
    size_t2 = t2.size_type || @collection_default_size_t
    assignable_PIntegerType(size_t, size_t2)
  when Types::PTupleType
    # compute the tuple's min/max size, and check if that size matches
    from, to = size_range(t2.size_type)
    t2s = Types::PIntegerType.new()
    t2s.from = t2.types.size - 1 + from
    t2s.to = t2.types.size - 1 + to
    assignable_PIntegerType(size_t, t2s)
  when Types::PStructType
    from = to = t2.elements.size
    t2s = Types::PIntegerType.new()
    t2s.from = from
    t2s.to = to
    assignable_PIntegerType(size_t, t2s)
  else
    false
  end
end

#assignable_PDataType(t, t2) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Data is assignable by other Data and by Array and Hash[Scalar, Data]



1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
# File 'lib/puppet/pops/types/type_calculator.rb', line 1542

def assignable_PDataType(t, t2)
  # We cannot put the NotUndefType[Data] in the @data_variant_t since that causes an endless recursion
  case t2
  when Types::PDataType
    true
  when Types::PNotUndefType
    assignable?(t, t2.type || @t)
  else
    assignable?(@data_variant_t, t2)
  end
end

#assignable_PDefaultType(t, t2) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1037
1038
1039
1040
# File 'lib/puppet/pops/types/type_calculator.rb', line 1037

def assignable_PDefaultType(t, t2)
  # Only default is assignable to default type
  t2.is_a?(Types::PDefaultType)
end

#assignable_PEnumType(t, t2) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
# File 'lib/puppet/pops/types/type_calculator.rb', line 1292

def assignable_PEnumType(t, t2)
  return true if t == t2
  if t.values.empty?
    return true if t2.is_a?(Types::PStringType) || t2.is_a?(Types::PEnumType) || t2.is_a?(Types::PPatternType)
  end
  case t2
  when Types::PStringType
    # if the set of strings are all found in the set of enums
    !t2.values.empty?() && t2.values.all? { |s| t.values.any? { |e| e == s }}
  when Types::PVariantType
    t2.types.all? {|variant_t| assignable_PEnumType(t, variant_t) }
  when Types::PEnumType
    # empty means any enum
    return true if t.values.empty?
    !t2.values.empty? && t2.values.all? { |s| t.values.any? {|e| e == s }}
  else
    false
  end
end

#assignable_PFloatType(t, t2) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1383
1384
1385
1386
1387
1388
1389
# File 'lib/puppet/pops/types/type_calculator.rb', line 1383

def assignable_PFloatType(t, t2)
  return false unless t2.is_a?(Types::PFloatType)
  trange =  from_to_ordered(t.from, t.to)
  t2range = from_to_ordered(t2.from, t2.to)
  # If t2 min and max are within the range of t
  trange[0] <= t2range[0] && trange[1] >= t2range[1]
end

#assignable_PHashType(t, t2) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Hash is assignable if t2 is a Hash and t2’s key and element types are assignable



1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
# File 'lib/puppet/pops/types/type_calculator.rb', line 1494

def assignable_PHashType(t, t2)
  case t2
  when Types::PHashType
    return true if (t.size_type.nil? || t.size_type.from == 0) && t2.is_the_empty_hash?
    return false unless t.key_type.nil? || assignable?(t.key_type, t2.key_type || @t)
    return false unless t.element_type.nil? || assignable?(t.element_type, t2.element_type || @t)
    assignable_PCollectionType(t, t2)
  when Types::PStructType
    # hash must accept String as key type
    # hash must accept all value types
    # hash must accept the size of the struct
    size_t = t.size_type || @collection_default_size_t
    min, max = size_t.range
    struct_size = t2.elements.size
    key_type = t.key_type
    element_type = t.element_type
    ( struct_size >= min && struct_size <= max &&
      t2.elements.all? {|e| (key_type.nil? || instance_of(key_type, e.name)) && (element_type.nil? || assignable?(element_type, e.value_type)) })
  else
    false
  end
end

#assignable_PHostClassType(t1, t2) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1523
1524
1525
1526
1527
1528
1529
# File 'lib/puppet/pops/types/type_calculator.rb', line 1523

def assignable_PHostClassType(t1, t2)
  return false unless t2.is_a?(Types::PHostClassType)
  # Class = Class[name}, Class[name] != Class
  return true if t1.class_name.nil?
  # Class[name] = Class[name]
  return t1.class_name == t2.class_name
end

#assignable_PIntegerType(t, t2) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1053
1054
1055
1056
1057
1058
1059
# File 'lib/puppet/pops/types/type_calculator.rb', line 1053

def assignable_PIntegerType(t, t2)
  return false unless t2.is_a?(Types::PIntegerType)
  trange =  from_to_ordered(t.from, t.to)
  t2range = from_to_ordered(t2.from, t2.to)
  # If t2 min and max are within the range of t
  trange[0] <= t2range[0] && trange[1] >= t2range[1]
end

#assignable_PNotUndefType(t, t2) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1020
1021
1022
# File 'lib/puppet/pops/types/type_calculator.rb', line 1020

def assignable_PNotUndefType(t, t2)
  !assignable?(t2, @nil_t) && (t.type.nil? || assignable?(t.type, t2))
end

#assignable_PNumericType(t, t2) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1048
1049
1050
# File 'lib/puppet/pops/types/type_calculator.rb', line 1048

def assignable_PNumericType(t, t2)
  t2.is_a?(Types::PNumericType)
end

#assignable_POptionalType(t, t2) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1281
1282
1283
1284
1285
1286
1287
1288
1289
# File 'lib/puppet/pops/types/type_calculator.rb', line 1281

def assignable_POptionalType(t, t2)
  return true if t2.is_a?(Types::PUndefType)
  return true if t.optional_type.nil?
  if t2.is_a?(Types::POptionalType)
    assignable?(t.optional_type, t2.optional_type || @t)
  else
    assignable?(t.optional_type, t2)
  end
end

#assignable_PPatternType(t, t2) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
# File 'lib/puppet/pops/types/type_calculator.rb', line 1358

def assignable_PPatternType(t, t2)
  return true if t == t2
  case t2
  when Types::PStringType, Types::PEnumType
    values = t2.values
  when Types::PVariantType
    return t2.types.all? {|variant_t| assignable_PPatternType(t, variant_t) }
  when Types::PPatternType
    return t.patterns.empty? ? true : false
  else
    return false
  end

  if t2.values.empty?
    # Strings / Enums (unknown which ones) cannot all match a pattern, but if there is no pattern it is ok
    # (There should really always be a pattern, but better safe than sorry).
    return t.patterns.empty? ? true : false
  end
  # all strings in String/Enum type must match one of the patterns in Pattern type,
  # or Pattern represents all Patterns == all Strings
  regexps = t.patterns.map {|p| p.regexp }
  regexps.empty? || t2.values.all? { |v| regexps.any? {|re| re.match(v) } }
end

#assignable_PRegexpType(t, t2) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1397
1398
1399
# File 'lib/puppet/pops/types/type_calculator.rb', line 1397

def assignable_PRegexpType(t, t2)
  t2.is_a?(Types::PRegexpType) && (t.pattern.nil? || t.pattern == t2.pattern)
end

#assignable_PResourceType(t1, t2) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1532
1533
1534
1535
1536
1537
1538
# File 'lib/puppet/pops/types/type_calculator.rb', line 1532

def assignable_PResourceType(t1, t2)
  return false unless t2.is_a?(Types::PResourceType)
  return true if t1.type_name.nil?
  return false if t1.type_name != t2.type_name
  return true if t1.title.nil?
  return t1.title == t2.title
end

#assignable_PRuntimeType(t1, t2) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Assignable if t2’s has the same runtime and the runtime name resolves to a class that is the same or subclass of t1’s resolved runtime type name



1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
# File 'lib/puppet/pops/types/type_calculator.rb', line 1557

def assignable_PRuntimeType(t1, t2)
  return false unless t2.is_a?(Types::PRuntimeType)
  return false unless t1.runtime == t2.runtime
  return true if t1.runtime_type_name.nil?   # t1 is wider
  return false if t2.runtime_type_name.nil?  # t1 not nil, so t2 can not be wider

  # NOTE: This only supports Ruby, must change when/if the set of runtimes is expanded
  c1 = class_from_string(t1.runtime_type_name)
  c2 = class_from_string(t2.runtime_type_name)
  return false unless c1.is_a?(Class) && c2.is_a?(Class)
  !!(c2 <= c1)
end

#assignable_PScalarType(t, t2) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1043
1044
1045
# File 'lib/puppet/pops/types/type_calculator.rb', line 1043

def assignable_PScalarType(t, t2)
  t2.is_a?(Types::PScalarType)
end

#assignable_PStringType(t, t2) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
# File 'lib/puppet/pops/types/type_calculator.rb', line 1313

def assignable_PStringType(t, t2)
  if t.values.empty?
    # A general string is assignable by any other string or pattern restricted string
    # if the string has a size constraint it does not match since there is no reasonable way
    # to compute the min/max length a pattern will match. For enum, it is possible to test that
    # each enumerator value is within range
    size_t = t.size_type || @collection_default_size_t
    case t2
    when Types::PStringType
      # true if size compliant
      size_t2 = t2.size_type || @collection_default_size_t
      assignable_PIntegerType(size_t, size_t2)

    when Types::PPatternType
      # true if size constraint is at least 0 to +Infinity (which is the same as the default)
      assignable_PIntegerType(size_t, @collection_default_size_t)

    when Types::PEnumType
      if t2.values && !t2.values.empty?
        # true if all enum values are within range
        min, max = t2.values.map(&:size).minmax
        trange =  from_to_ordered(size_t.from, size_t.to)
        t2range = [min, max]
        # If t2 min and max are within the range of t
        trange[0] <= t2range[0] && trange[1] >= t2range[1]
      else
        # enum represents all enums, and thus all strings, a sized constrained string can thus not
        # be assigned any enum (unless it is max size).
        assignable_PIntegerType(size_t, @collection_default_size_t)
      end
    else
      # no other type matches string
      false
    end
  elsif t2.is_a?(Types::PStringType)
    # A specific string acts as a set of strings - must have exactly the same strings
    # In this case, size does not matter since the definition is very precise anyway
    Set.new(t.values) == Set.new(t2.values)
  else
    # All others are false, since no other type describes the same set of specific strings
    false
  end
end

#assignable_PStructType(t, t2) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
# File 'lib/puppet/pops/types/type_calculator.rb', line 1245

def assignable_PStructType(t, t2)
  if t2.is_a?(Types::PStructType)
    h2 = t2.hashed_elements
    matched = 0
    t.elements.all? do |e1|
      e2 = h2[e1.name]
      if e2.nil?
        assignable?(e1.key_type, @nil_t)
      else
        matched += 1
        assignable?(e1.key_type, e2.key_type) && assignable?(e1.value_type, e2.value_type)
      end
    end && matched == h2.size
  elsif t2.is_a?(Types::PHashType)
    required = 0
    required_elements_assignable = t.elements.all? do |e|
      if assignable?(e.key_type, @nil_t)
        true
      else
        required += 1
        assignable?(e.value_type, t2.element_type)
      end
    end
    if required_elements_assignable
      size_t2 = t2.size_type || @collection_default_size_t
      size_t = Types::PIntegerType.new
      size_t.from = required
      size_t.to = t.elements.size
      assignable_PIntegerType(size_t, size_t2)
    end
  else
    false
  end
end

#assignable_PTupleType(t, t2) ⇒ Object



1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
# File 'lib/puppet/pops/types/type_calculator.rb', line 1189

def assignable_PTupleType(t, t2)
  return true if t == t2 || t.types.empty? && (t2.is_a?(Types::PArrayType))
  size_t = t.size_type || Puppet::Pops::Types::TypeFactory.range(*t.size_range)

  if t2.is_a?(Types::PTupleType)
    size_t2 = t2.size_type || Puppet::Pops::Types::TypeFactory.range(*t2.size_range)

    # not assignable if the number of types in t2 is outside number of types in t1
    if assignable?(size_t, size_t2)
      t2.types.size.times do |index|
        return false unless assignable?((t.types[index] || t.types[-1]), t2.types[index])
      end
      return true
    else
      return false
    end
  elsif t2.is_a?(Types::PArrayType)
    t2_entry = t2.element_type

    # Array of anything can not be assigned (unless tuple is tuple of anything) - this case
    # was handled at the top of this method.
    #
    return false if t2_entry.nil?
    size_t = t.size_type || Puppet::Pops::Types::TypeFactory.range(*t.size_range)
    size_t2 = t2.size_type || @collection_default_size_t
    return false unless assignable?(size_t, size_t2)
    min(t.types.size, size_t2.range()[1]).times do |index|
      return false unless assignable?((t.types[index] || t.types[-1]), t2_entry)
    end
    true
  else
    false
  end
end

#assignable_PType(t, t2) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1444
1445
1446
1447
1448
1449
# File 'lib/puppet/pops/types/type_calculator.rb', line 1444

def assignable_PType(t, t2)
  return false unless t2.is_a?(Types::PType)
  return true if t.type.nil? # wide enough to handle all types
  return false if t2.type.nil? # wider than t
  assignable?(t.type, t2.type)
end

#assignable_PUndefType(t, t2) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1025
1026
1027
1028
# File 'lib/puppet/pops/types/type_calculator.rb', line 1025

def assignable_PUndefType(t, t2)
  # Only undef/nil is assignable to nil type
  t2.is_a?(Types::PUndefType)
end

#assignable_PUnitType(t, t2) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Anything is assignable to a Unit type



1032
1033
1034
# File 'lib/puppet/pops/types/type_calculator.rb', line 1032

def assignable_PUnitType(t, t2)
  true
end

#assignable_PVariantType(t, t2) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
# File 'lib/puppet/pops/types/type_calculator.rb', line 1091

def assignable_PVariantType(t, t2)
  # Data is a specific variant
  t2 = @data_variant_t if t2.is_a?(Types::PDataType)
  if t2.is_a?(Types::PVariantType)
    # A variant is assignable if all of its options are assignable to one of this type's options
    return true if t == t2
    t2.types.all? do |other|
      # if the other is a Variant, all of its options, but be assignable to one of this type's options
      other = other.is_a?(Types::PDataType) ? @data_variant_t : other
      if other.is_a?(Types::PVariantType)
        assignable?(t, other)
      else
        t.types.any? {|option_t| assignable?(option_t, other) }
      end
    end
  else
    # A variant is assignable if t2 is assignable to any of its types
    t.types.any? { |option_t| assignable?(option_t, t2) }
  end
end

#callable?(callable, args) ⇒ Boolean

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

Returns:

  • (Boolean)


297
298
299
300
301
# File 'lib/puppet/pops/types/type_calculator.rb', line 297

def callable?(callable, args)
  return false if !self.class.is_kind_of_callable?(callable)
  # Note that polymorphism is for the args type, the callable is always a callable
  @@callable_visitor.visit_this_1(self, args, callable)
end

#callable_Object(o, callable_t) ⇒ Object

Catch all not callable combinations



1113
1114
1115
# File 'lib/puppet/pops/types/type_calculator.rb', line 1113

def callable_Object(o, callable_t)
  false
end

#callable_PArrayType(args_array, callable_t) ⇒ Object



1165
1166
1167
1168
1169
# File 'lib/puppet/pops/types/type_calculator.rb', line 1165

def callable_PArrayType(args_array, callable_t)
  return false unless assignable?(callable_t.param_types, args_array)
  # does not support calling with a block, but have to check that callable is ok with missing block
  assignable?(callable_t.block_type || @nil_t, @nil_t)
end

#callable_PCallableType(given_callable_t, required_callable_t) ⇒ Object



1176
1177
1178
1179
# File 'lib/puppet/pops/types/type_calculator.rb', line 1176

def callable_PCallableType(given_callable_t, required_callable_t)
  # If the required callable is euqal or more specific than the given, the given is callable
  assignable?(required_callable_t, given_callable_t)
end

#callable_PTupleType(args_tuple, callable_t) ⇒ Object



1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
# File 'lib/puppet/pops/types/type_calculator.rb', line 1117

def callable_PTupleType(args_tuple, callable_t)
  if args_tuple.size_type
    raise ArgumentError, "Callable tuple may not have a size constraint when used as args"
  end
  # Assume no block was given - i.e. it is nil, and its type is PUndefType
  block_t = @nil_t
  if self.class.is_kind_of_callable?(args_tuple.types.last)
    # a split is needed to make it possible to use required, optional, and varargs semantics
    # of the tuple type.
    #
    args_tuple = args_tuple.copy
    # to drop the callable, it must be removed explicitly since this is an rgen array
    args_tuple.removeTypes(block_t = args_tuple.types.last())
  else
    # no block was given, if it is required, the below will fail
  end
  # unless argument types match parameter types
  return false unless assignable?(callable_t.param_types, args_tuple)
  # can the given block be *called* with a signature requirement specified by callable_t?
  assignable?(callable_t.block_type || @nil_t, block_t)
end

#callable_PUndefType(nil_t, callable_t) ⇒ Object



1171
1172
1173
1174
# File 'lib/puppet/pops/types/type_calculator.rb', line 1171

def callable_PUndefType(nil_t, callable_t)
  # if callable_t is Optional (or indeed PUndefType), this means that 'missing callable' is accepted
  assignable?(callable_t, nil_t)
end

#common_type(t1, t2) ⇒ Object

Answers, ‘What is the common type of t1 and t2?’

TODO: The current implementation should be optimized for performance

Raises:

  • (ArgumentError)


559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
# File 'lib/puppet/pops/types/type_calculator.rb', line 559

def common_type(t1, t2)
  raise ArgumentError, 'two types expected' unless (is_ptype?(t1) || is_pnil?(t1)) && (is_ptype?(t2) || is_pnil?(t2))

  # TODO: This is not right since Scalar U Undef is Any
  # if either is nil, the common type is the other
  if is_pnil?(t1)
    return t2
  elsif is_pnil?(t2)
    return t1
  end

  # If either side is Unit, it is the other type
  if t1.is_a?(Types::PUnitType)
    return t2
  elsif t2.is_a?(Types::PUnitType)
    return t1
  end

  # Simple case, one is assignable to the other
  if assignable?(t1, t2)
    return t1
  elsif assignable?(t2, t1)
    return t2
  end

  # when both are arrays, return an array with common element type
  if t1.is_a?(Types::PArrayType) && t2.is_a?(Types::PArrayType)
    type = Types::PArrayType.new()
    type.element_type = common_type(t1.element_type, t2.element_type)
    return type
  end

  # when both are hashes, return a hash with common key- and element type
  if t1.is_a?(Types::PHashType) && t2.is_a?(Types::PHashType)
    type = Types::PHashType.new()
    type.key_type = common_type(t1.key_type, t2.key_type)
    type.element_type = common_type(t1.element_type, t2.element_type)
    return type
  end

  # when both are host-classes, reduce to PHostClass[] (since one was not assignable to the other)
  if t1.is_a?(Types::PHostClassType) && t2.is_a?(Types::PHostClassType)
    return Types::PHostClassType.new()
  end

  # when both are resources, reduce to Resource[T] or Resource[] (since one was not assignable to the other)
  if t1.is_a?(Types::PResourceType) && t2.is_a?(Types::PResourceType)
    result = Types::PResourceType.new()
    # only Resource[] unless the type name is the same
    if t1.type_name == t2.type_name then result.type_name = t1.type_name end
    # the cross assignability test above has already determined that they do not have the same type and title
    return result
  end

  # Integers have range, expand the range to the common range
  if t1.is_a?(Types::PIntegerType) && t2.is_a?(Types::PIntegerType)
    t1range = from_to_ordered(t1.from, t1.to)
    t2range = from_to_ordered(t2.from, t2.to)
    t = Types::PIntegerType.new()
    from = [t1range[0], t2range[0]].min
    to = [t1range[1], t2range[1]].max
    t.from = from unless from == TheInfinity
    t.to = to unless to == TheInfinity
    return t
  end

  # Floats have range, expand the range to the common range
  if t1.is_a?(Types::PFloatType) && t2.is_a?(Types::PFloatType)
    t1range = from_to_ordered(t1.from, t1.to)
    t2range = from_to_ordered(t2.from, t2.to)
    t = Types::PFloatType.new()
    from = [t1range[0], t2range[0]].min
    to = [t1range[1], t2range[1]].max
    t.from = from unless from == TheInfinity
    t.to = to unless to == TheInfinity
    return t
  end

  if t1.is_a?(Types::PStringType) && t2.is_a?(Types::PStringType)
    t = Types::PStringType.new()
    t.values = t1.values | t2.values unless t1.values.empty? || t2.values.empty?
    t.size_type = common_type(t1.size_type, t2.size_type) unless t1.size_type.nil? || t2.size_type.nil?
    return t
  end

  if t1.is_a?(Types::PPatternType) && t2.is_a?(Types::PPatternType)
    t = Types::PPatternType.new()
    # must make copies since patterns are contained types, not data-types
    t.patterns = (t1.patterns | t2.patterns).map(&:copy)
    return t
  end

  if t1.is_a?(Types::PEnumType) && t2.is_a?(Types::PEnumType)
    # The common type is one that complies with either set
    t = Types::PEnumType.new
    t.values = t1.values | t2.values
    return t
  end

  if t1.is_a?(Types::PVariantType) && t2.is_a?(Types::PVariantType)
    # The common type is one that complies with either set
    t = Types::PVariantType.new
    t.types = (t1.types | t2.types).map(&:copy)
    return t
  end

  if t1.is_a?(Types::PRegexpType) && t2.is_a?(Types::PRegexpType)
    # if they were identical, the general rule would return a parameterized regexp
    # since they were not, the result is a generic regexp type
    return Types::PPatternType.new()
  end

  if t1.is_a?(Types::PCallableType) && t2.is_a?(Types::PCallableType)
    # They do not have the same signature, and one is not assignable to the other,
    # what remains is the most general form of Callable
    return Types::PCallableType.new()
  end

  # Common abstract types, from most specific to most general
  if common_numeric?(t1, t2)
    return Types::PNumericType.new()
  end

  if common_scalar?(t1, t2)
    return Types::PScalarType.new()
  end

  if common_data?(t1,t2)
    return Types::PDataType.new()
  end

  # Meta types Type[Integer] + Type[String] => Type[Data]
  if t1.is_a?(Types::PType) && t2.is_a?(Types::PType)
    type = Types::PType.new()
    type.type = common_type(t1.type, t2.type)
    return type
  end

  # If both are Runtime types
  if t1.is_a?(Types::PRuntimeType) && t2.is_a?(Types::PRuntimeType)
    if t1.runtime == t2.runtime && t1.runtime_type_name == t2.runtime_type_name
      return t1
    end
    # finding the common super class requires that names are resolved to class
    # NOTE: This only supports runtime type of :ruby
    c1 = Types::ClassLoader.provide_from_type(t1)
    c2 = Types::ClassLoader.provide_from_type(t2)
    if c1 && c2
      c2_superclasses = superclasses(c2)
      superclasses(c1).each do|c1_super|
        c2_superclasses.each do |c2_super|
          if c1_super == c2_super
            return Types::PRuntimeType.new(:runtime => :ruby, :runtime_type_name => c1_super.name)
          end
        end
      end
    end
  end

  # They better both be Any type, or the wrong thing was asked and nil is returned
  if t1.is_a?(Types::PAnyType) && t2.is_a?(Types::PAnyType)
    return Types::PAnyType.new()
  end
end

#dataObject

Convenience method to get a data type for comparisons



221
222
223
# File 'lib/puppet/pops/types/type_calculator.rb', line 221

def data
  @data_t
end

#data_variantObject

Convenience method to get a variant compatible with the Data type.



228
229
230
# File 'lib/puppet/pops/types/type_calculator.rb', line 228

def data_variant
  @data_variant_t
end

#debug_string(t) ⇒ Object

Produces a debug string representing the type (possibly with more information that the regular string format)



744
745
746
# File 'lib/puppet/pops/types/type_calculator.rb', line 744

def debug_string(t)
  @@inspect_visitor.visit_this_0(self, t)
end

#debug_string_Object(t) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1571
1572
1573
# File 'lib/puppet/pops/types/type_calculator.rb', line 1571

def debug_string_Object(t)
  string(t)
end

#debug_string_PStringType(t) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1657
1658
1659
1660
1661
# File 'lib/puppet/pops/types/type_calculator.rb', line 1657

def debug_string_PStringType(t)
  range = range_array_part(t.size_type)
  range_part = range.empty? ? '' : '[' << range.join(' ,') << '], '
  "String[" << range_part << (t.values.map {|s| "'#{s}'" }).join(', ') << ']'
end

#enumerable(t) ⇒ Object

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



291
292
293
# File 'lib/puppet/pops/types/type_calculator.rb', line 291

def enumerable(t)
  @@enumerable_visitor.visit_this_0(self, t)
end

#enumerable_Object(o) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Catches all non enumerable types



1826
1827
1828
# File 'lib/puppet/pops/types/type_calculator.rb', line 1826

def enumerable_Object(o)
  nil
end

#enumerable_PIntegerType(t) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1831
1832
1833
1834
1835
# File 'lib/puppet/pops/types/type_calculator.rb', line 1831

def enumerable_PIntegerType(t)
  # Not enumerable if representing an infinite range
  return nil if t.size == TheInfinity
  t
end

#equals(left, right) ⇒ Object

Answers if the two given types describe the same type



304
305
306
307
308
309
310
# File 'lib/puppet/pops/types/type_calculator.rb', line 304

def equals(left, right)
  return false unless left.is_a?(Types::PAnyType) && right.is_a?(Types::PAnyType)
  # Types compare per class only - an extra test must be made if the are mutually assignable
  # to find all types that represent the same type of instance
  #
  left == right || (assignable?(right, left) && assignable?(left, right))
end

#from_to_ordered(from, to) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1080
1081
1082
1083
1084
1085
1086
1087
1088
# File 'lib/puppet/pops/types/type_calculator.rb', line 1080

def from_to_ordered(from, to)
  x = (from.nil? || from == :default) ? -TheInfinity : from
  y = (to.nil? || to == :default) ? TheInfinity : to
  if x < y
    [x, y]
  else
    [y, x]
  end
end

#generalize!(o) ⇒ Object

Generalizes value specific types. The given type is mutated and returned.



354
355
356
357
358
# File 'lib/puppet/pops/types/type_calculator.rb', line 354

def generalize!(o)
  @@generalize_visitor.visit_this_0(self, o)
  o.eAllContents.each { |x| @@generalize_visitor.visit_this_0(self, x) }
  o
end

#generalize_Object(o) ⇒ Object



360
361
362
# File 'lib/puppet/pops/types/type_calculator.rb', line 360

def generalize_Object(o)
  # do nothing, there is nothing to change for most types
end

#generalize_PCollectionType(o) ⇒ Object



383
384
385
386
387
# File 'lib/puppet/pops/types/type_calculator.rb', line 383

def generalize_PCollectionType(o)
  # erase the size constraint from Array and Hash (if one exists, it is transformed to -Infinity - + Infinity, which is
  # not desirable.
  o.size_type = nil
end

#generalize_PFloatType(o) ⇒ Object



389
390
391
392
# File 'lib/puppet/pops/types/type_calculator.rb', line 389

def generalize_PFloatType(o)
  o.to = nil
  o.from = nil
end

#generalize_PIntegerType(o) ⇒ Object



394
395
396
397
# File 'lib/puppet/pops/types/type_calculator.rb', line 394

def generalize_PIntegerType(o)
  o.to = nil
  o.from = nil
end

#generalize_PStringType(o) ⇒ Object



375
376
377
378
379
380
381
# File 'lib/puppet/pops/types/type_calculator.rb', line 375

def generalize_PStringType(o)
  # Skip generalization if the string is contained in a PStructElement key.
  unless is_struct_element_key?(o)
    o.values = []
    o.size_type = nil
  end
end

#infer(o) ⇒ Object

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).



403
404
405
# File 'lib/puppet/pops/types/type_calculator.rb', line 403

def infer(o)
  @@infer_visitor.visit_this_0(self, o)
end

#infer_and_reduce_type(enumerable) ⇒ Object

Reduce an enumerable of objects to a single common type



759
760
761
# File 'lib/puppet/pops/types/type_calculator.rb', line 759

def infer_and_reduce_type(enumerable)
  reduce_type(enumerable.collect() {|o| infer(o) })
end

#infer_Array(o) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



920
921
922
923
924
925
926
927
928
929
930
# File 'lib/puppet/pops/types/type_calculator.rb', line 920

def infer_Array(o)
  type = Types::PArrayType.new()
  type.element_type =
  if o.empty?
    Types::PUndefType.new()
  else
    infer_and_reduce_type(o)
  end
  type.size_type = size_as_type(o)
  type
end

#infer_Class(o) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

The type of all classes is PType



766
767
768
# File 'lib/puppet/pops/types/type_calculator.rb', line 766

def infer_Class(o)
  Types::PType.new()
end

#infer_Closure(o) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



771
772
773
# File 'lib/puppet/pops/types/type_calculator.rb', line 771

def infer_Closure(o)
  o.type()
end

#infer_FalseClass(o) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



900
901
902
# File 'lib/puppet/pops/types/type_calculator.rb', line 900

def infer_FalseClass(o)
  Types::PBooleanType.new()
end

#infer_Float(o) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



813
814
815
816
817
818
# File 'lib/puppet/pops/types/type_calculator.rb', line 813

def infer_Float(o)
  t = Types::PFloatType.new()
  t.from = o
  t.to = o
  t
end

#infer_Function(o) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



776
777
778
# File 'lib/puppet/pops/types/type_calculator.rb', line 776

def infer_Function(o)
  o.class.dispatcher.to_type
end

#infer_generic(o) ⇒ Object



407
408
409
410
# File 'lib/puppet/pops/types/type_calculator.rb', line 407

def infer_generic(o)
  result = generalize!(infer(o))
  result
end

#infer_Hash(o) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



933
934
935
936
937
938
939
940
941
942
943
944
945
946
# File 'lib/puppet/pops/types/type_calculator.rb', line 933

def infer_Hash(o)
  type = Types::PHashType.new()
  if o.empty?
    ktype = Types::PUndefType.new()
    etype = Types::PUndefType.new()
  else
    ktype = infer_and_reduce_type(o.keys())
    etype = infer_and_reduce_type(o.values())
  end
  type.key_type = ktype
  type.element_type = etype
  type.size_type = size_as_type(o)
  type
end

#infer_Integer(o) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



821
822
823
824
825
826
# File 'lib/puppet/pops/types/type_calculator.rb', line 821

def infer_Integer(o)
  t = Types::PIntegerType.new()
  t.from = o
  t.to = o
  t
end

#infer_NilClass(o) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



836
837
838
# File 'lib/puppet/pops/types/type_calculator.rb', line 836

def infer_NilClass(o)
  Types::PUndefType.new()
end

#infer_Object(o) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



781
782
783
# File 'lib/puppet/pops/types/type_calculator.rb', line 781

def infer_Object(o)
  Types::PRuntimeType.new(:runtime => :ruby, :runtime_type_name => o.class.name)
end

#infer_PAnyType(o) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

The type of all types is PType



788
789
790
791
792
# File 'lib/puppet/pops/types/type_calculator.rb', line 788

def infer_PAnyType(o)
  type = Types::PType.new()
  type.type = o.copy
  type
end

#infer_Proc(o) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Parameters:

  • o (Proc)


842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
# File 'lib/puppet/pops/types/type_calculator.rb', line 842

def infer_Proc(o)
  min = 0
  max = 0
  if o.respond_to?(:parameters)
    mapped_types = o.parameters.map do |p|
      param_t = Types::PAnyType.new
      case p[0]
      when :rest
        max = :default
        break param_t
      when :req
        min += 1
      end
      max += 1
    	param_t
    end
  else
    # Cannot correctly compute the signature in Ruby 1.8.7 because arity for
    # optional values is screwed up (there is no way to get the upper limit),
    # an optional looks the same as a varargs.
    arity = o.arity
    if arity < 0
      min = -arity - 1
      max = :default # i.e. infinite (which is wrong when there are optional - flaw in 1.8.7)
    else
      min = max = arity
    end
    mapped_types = Array.new(min) { Types::PAnyType.new }
  end
  if min == 0 || min != max
    mapped_types << min
    mapped_types << max
  end
  Types::TypeFactory.callable(*mapped_types)
end

#infer_PType(o) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

The type of all types is PType This is the metatype short circuit.



798
799
800
801
802
# File 'lib/puppet/pops/types/type_calculator.rb', line 798

def infer_PType(o)
  type = Types::PType.new()
  type.type = o.copy
  type
end

#infer_PuppetProc(o) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



879
880
881
# File 'lib/puppet/pops/types/type_calculator.rb', line 879

def infer_PuppetProc(o)
  infer_Closure(o.closure)
end

#infer_Regexp(o) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



829
830
831
832
833
# File 'lib/puppet/pops/types/type_calculator.rb', line 829

def infer_Regexp(o)
  t = Types::PRegexpType.new()
  t.pattern = o.source
  t
end

#infer_Resource(o) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

A Puppet::Parser::Resource, or Puppet::Resource



907
908
909
910
911
912
913
914
915
916
917
# File 'lib/puppet/pops/types/type_calculator.rb', line 907

def infer_Resource(o)
  t = Types::PResourceType.new()
  t.type_name = o.type.to_s.downcase
  # Only Puppet::Resource can have a title that is a symbol :undef, a PResource cannot.
  # A mapping must be made to empty string. A nil value will result in an error later
  title = o.title
  t.title = (:undef == title  ? '' : title)
  type = Types::PType.new()
  type.type = t
  type
end

#infer_set(o) ⇒ Object

Answers ‘what is the set of Puppet Types of o’



415
416
417
# File 'lib/puppet/pops/types/type_calculator.rb', line 415

def infer_set(o)
  @@infer_set_visitor.visit_this_0(self, o)
end

#infer_set_Array(o) ⇒ Object



961
962
963
964
965
966
967
968
969
970
971
# File 'lib/puppet/pops/types/type_calculator.rb', line 961

def infer_set_Array(o)
  if o.empty?
    type = Types::PArrayType.new()
    type.element_type = Types::PUndefType.new()
    type.size_type = size_as_type(o)
  else
    type = Types::PTupleType.new()
    type.types = o.map() {|x| infer_set(x) }
  end
  type
end

#infer_set_Hash(o) ⇒ Object



973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
# File 'lib/puppet/pops/types/type_calculator.rb', line 973

def infer_set_Hash(o)
  if o.empty?
    type = Types::PHashType.new
    type.key_type = Types::PUndefType.new
    type.element_type = Types::PUndefType.new
    type.size_type = size_as_type(o)
  elsif o.keys.all? {|k| instance_of_PStringType(@non_empty_string_t, k) }
    type = Types::PStructType.new
    type.elements = o.map do |k,v|
      element = Types::PStructElement.new
      element.key_type = infer_String(k)
      element.value_type = infer_set(v)
      element
    end
  else
    type = Types::PHashType.new
    ktype = Types::PVariantType.new
    ktype.types = o.keys.map {|k| infer_set(k) }
    etype = Types::PVariantType.new
    etype.types = o.values.map {|e| infer_set(e) }
    type.key_type = unwrap_single_variant(ktype)
    type.element_type = unwrap_single_variant(etype)
    type.size_type = size_as_type(o)
  end
  type
end

#infer_set_Object(o) ⇒ Object

Common case for everything that intrinsically only has a single type



957
958
959
# File 'lib/puppet/pops/types/type_calculator.rb', line 957

def infer_set_Object(o)
  infer(o)
end

#infer_String(o) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



805
806
807
808
809
810
# File 'lib/puppet/pops/types/type_calculator.rb', line 805

def infer_String(o)
  t = Types::PStringType.new()
  t.addValues(o)
  t.size_type = size_as_type(o)
  t
end

#infer_Symbol(o) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

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



885
886
887
888
889
890
891
892
# File 'lib/puppet/pops/types/type_calculator.rb', line 885

def infer_Symbol(o)
  case o
  when :default
    Types::PDefaultType.new()
  else
    infer_Object(o)
  end
end

#infer_TrueClass(o) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



895
896
897
# File 'lib/puppet/pops/types/type_calculator.rb', line 895

def infer_TrueClass(o)
  Types::PBooleanType.new()
end

#injectable_class(klazz) ⇒ Class?

Answers the question ‘is it possible to inject an instance of the given class’ A class is injectable if it has a special *assisted inject* class method called ‘inject` taking an injector and a scope as argument, or if it has a zero args `initialize` method.

Parameters:

Returns:

  • (Class, nil)

    the injectable Class, or nil if not injectable



244
245
246
247
248
249
250
251
252
253
254
255
256
257
# File 'lib/puppet/pops/types/type_calculator.rb', line 244

def injectable_class(klazz)
  # Handle case when we get a PType instead of a class
  if klazz.is_a?(Types::PRuntimeType)
    klazz = Puppet::Pops::Types::ClassLoader.provide(klazz)
  end

  # data types can not be injected (check again, it is not safe to assume that given RubyRuntime klazz arg was ok)
  return false unless type(klazz).is_a?(Types::PRuntimeType)
  if (klazz.respond_to?(:inject) && klazz.method(:inject).arity() == -4) || klazz.instance_method(:initialize).arity() == 0
    klazz
  else
    nil
  end
end

#instance?(t, o) ⇒ Boolean

Answers ‘is o an instance of type t’

Returns:

  • (Boolean)


535
536
537
# File 'lib/puppet/pops/types/type_calculator.rb', line 535

def instance?(t, o)
  instance_of(t,o)
end

#instance_of(t, o) ⇒ Object



419
420
421
# File 'lib/puppet/pops/types/type_calculator.rb', line 419

def instance_of(t, o)
  @@instance_of_visitor.visit_this_1(self, t, o)
end

#instance_of_Object(t, o) ⇒ Object



423
424
425
426
427
# File 'lib/puppet/pops/types/type_calculator.rb', line 423

def instance_of_Object(t, o)
  # Undef is Undef and Any, but nothing else when checking instance?
  return false if (o.nil?) && t.class != Types::PAnyType
  assignable?(t, infer(o))
end

#instance_of_PArrayType(t, o) ⇒ Object



435
436
437
438
439
440
441
# File 'lib/puppet/pops/types/type_calculator.rb', line 435

def instance_of_PArrayType(t, o)
  return false unless o.is_a?(Array)
  return false unless o.all? {|element| instance_of(t.element_type, element) }
  size_t = t.size_type || @collection_default_size_t
  # optimize by calling directly
  return instance_of_PIntegerType(size_t, o.size)
end

#instance_of_PDataType(t, o) ⇒ Object



504
505
506
# File 'lib/puppet/pops/types/type_calculator.rb', line 504

def instance_of_PDataType(t, o)
  instance_of(@data_variant_t, o)
end

#instance_of_PHashType(t, o) ⇒ Object



494
495
496
497
498
499
500
501
502
# File 'lib/puppet/pops/types/type_calculator.rb', line 494

def instance_of_PHashType(t, o)
  return false unless o.is_a?(Hash)
  key_t = t.key_type
  element_t = t.element_type
  return false unless o.keys.all? {|key| instance_of(key_t, key) } && o.values.all? {|value| instance_of(element_t, value) }
  size_t = t.size_type || @collection_default_size_t
  # optimize by calling directly
  return instance_of_PIntegerType(size_t, o.size)
end

#instance_of_PIntegerType(t, o) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



444
445
446
447
448
449
450
451
# File 'lib/puppet/pops/types/type_calculator.rb', line 444

def instance_of_PIntegerType(t, o)
  return false unless o.is_a?(Integer)
  x = t.from
  x = -Float::INFINITY if x.nil? || x == :default
  y = t.to
  y = Float::INFINITY if y.nil? || y == :default
  return x < y ? x <= o && y >= o : y <= o && x >= o
end

#instance_of_PNotUndefType(t, o) ⇒ Object



508
509
510
# File 'lib/puppet/pops/types/type_calculator.rb', line 508

def instance_of_PNotUndefType(t, o)
  !(o.nil? || o == :undef) && (t.type.nil? || instance_of(t.type, o))
end

#instance_of_POptionalType(t, o) ⇒ Object



516
517
518
# File 'lib/puppet/pops/types/type_calculator.rb', line 516

def instance_of_POptionalType(t, o)
  instance_of_PUndefType(t, o) || instance_of(t.optional_type, o)
end

#instance_of_PStringType(t, o) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



454
455
456
457
458
459
460
461
462
463
464
# File 'lib/puppet/pops/types/type_calculator.rb', line 454

def instance_of_PStringType(t, o)
  return false unless o.is_a?(String)
  # true if size compliant
  size_t = t.size_type
  if size_t.nil? || instance_of_PIntegerType(size_t, o.size)
    values = t.values
    values.empty? || values.include?(o)
  else
    false
  end
end

#instance_of_PStructType(t, o) ⇒ Object



478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
# File 'lib/puppet/pops/types/type_calculator.rb', line 478

def instance_of_PStructType(t, o)
  return false unless o.is_a?(Hash)
  matched = 0
  t.elements.all? do |e|
    key = e.name
    v = o[key]
    if v.nil? && !o.include?(key)
      # Entry is missing. Only OK when key is optional
      assignable?(e.key_type, @nil_t)
    else
      matched += 1
      instance_of(e.value_type, v)
    end
  end && matched == o.size
end

#instance_of_PTupleType(t, o) ⇒ Object



466
467
468
469
470
471
472
473
474
475
476
# File 'lib/puppet/pops/types/type_calculator.rb', line 466

def instance_of_PTupleType(t, o)
  return false unless o.is_a?(Array)
  # compute the tuple's min/max size, and check if that size matches
  size_t = t.size_type || Puppet::Pops::Types::TypeFactory.range(*t.size_range)

  return false unless instance_of_PIntegerType(size_t, o.size)
  o.each_with_index do |element, index|
     return false unless instance_of(t.types[index] || t.types[-1], element)
  end
  true
end

#instance_of_PUndefType(t, o) ⇒ Object



512
513
514
# File 'lib/puppet/pops/types/type_calculator.rb', line 512

def instance_of_PUndefType(t, o)
  o.nil? || o == :undef
end

#instance_of_PUnitType(t, o) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Anything is an instance of Unit



431
432
433
# File 'lib/puppet/pops/types/type_calculator.rb', line 431

def instance_of_PUnitType(t, o)
  true
end

#instance_of_PVariantType(t, o) ⇒ Object



520
521
522
523
# File 'lib/puppet/pops/types/type_calculator.rb', line 520

def instance_of_PVariantType(t, o)
  # instance of variant if o is instance? of any of variant's types
  t.types.any? { |option_t| instance_of(option_t, o) }
end

#is_pnil?(t) ⇒ Boolean

Answers if t represents the puppet type PUndefType

Returns:

  • (Boolean)


549
550
551
# File 'lib/puppet/pops/types/type_calculator.rb', line 549

def is_pnil?(t)
  return t.nil? || t.is_a?(Types::PUndefType)
end

#is_ptype?(t) ⇒ Boolean

Answers if t is a puppet type

Returns:

  • (Boolean)


542
543
544
# File 'lib/puppet/pops/types/type_calculator.rb', line 542

def is_ptype?(t)
  return t.is_a?(Types::PAnyType)
end

#max(a, b) ⇒ Object



1181
1182
1183
# File 'lib/puppet/pops/types/type_calculator.rb', line 1181

def max(a,b)
  a >=b ? a : b
end

#min(a, b) ⇒ Object



1185
1186
1187
# File 'lib/puppet/pops/types/type_calculator.rb', line 1185

def min(a,b)
  a <= b ? a : b
end

#range_array_part(t) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Produces a string from an Integer range type that is used inside other type strings



1625
1626
1627
1628
# File 'lib/puppet/pops/types/type_calculator.rb', line 1625

def range_array_part(t)
  return [] if t.nil? || (t.from.nil? && t.to.nil?)
  [t.from.nil? ? 'default' : t.from , t.to.nil? ? 'default' : t.to ]
end

#reduce_type(enumerable) ⇒ Object

Reduces an enumerable of types to a single common type.



752
753
754
# File 'lib/puppet/pops/types/type_calculator.rb', line 752

def reduce_type(enumerable)
  enumerable.reduce(nil) {|memo, t| common_type(memo, t) }
end

#size_as_type(collection) ⇒ Object



948
949
950
951
952
953
954
# File 'lib/puppet/pops/types/type_calculator.rb', line 948

def size_as_type(collection)
  size = collection.size
  t = Types::PIntegerType.new()
  t.from = size
  t.to = size
  t
end

#size_range(range) ⇒ Object

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



1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
# File 'lib/puppet/pops/types/type_calculator.rb', line 1066

def size_range(range)
  return [1,1] if range.nil?
  from = range.from
  to = range.to
  x = from.nil? ? 1 : from
  y = to.nil? ? TheInfinity : to
  if x < y
    [x, y]
  else
    [y, x]
  end
end

#string(t) ⇒ Object

Produces a string representing the type



737
738
739
# File 'lib/puppet/pops/types/type_calculator.rb', line 737

def string(t)
  @@string_visitor.visit_this_0(self, t)
end

#string_NilClass(t) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1585
# File 'lib/puppet/pops/types/type_calculator.rb', line 1585

def string_NilClass(t)     ; '?'       ; end

#string_PAnyType(t) ⇒ Object



1593
# File 'lib/puppet/pops/types/type_calculator.rb', line 1593

def string_PAnyType(t)     ; "Any"     ; end

#string_PArrayType(t) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1759
1760
1761
1762
# File 'lib/puppet/pops/types/type_calculator.rb', line 1759

def string_PArrayType(t)
  parts = [string(t.element_type)] + range_array_part(t.size_type)
  "Array[#{parts.join(', ')}]"
end

#string_PBooleanType(t) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1602
# File 'lib/puppet/pops/types/type_calculator.rb', line 1602

def string_PBooleanType(t) ; "Boolean" ; end

#string_PCallableType(t) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
# File 'lib/puppet/pops/types/type_calculator.rb', line 1688

def string_PCallableType(t)
  # generic
  return "Callable" if t.param_types.nil?

  if t.param_types.types.empty?
    range = [0, 0]
  else
    range = range_array_part(t.param_types.size_type)
  end
  # translate to string, and skip Unit types
  types = t.param_types.types.map {|t2| string(t2) unless t2.class == Types::PUnitType }.compact

  s = "Callable[" << types.join(', ')
  unless range.empty?
    (s << ', ') unless types.empty?
    s << range.join(', ')
  end
  # Add block T last (after min, max) if present)
  #
  unless t.block_type.nil?
    (s << ', ') unless types.empty? && range.empty?
    s << string(t.block_type)
  end
  s << "]"
  s
end

#string_PCatalogEntryType(t) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1771
1772
1773
# File 'lib/puppet/pops/types/type_calculator.rb', line 1771

def string_PCatalogEntryType(t)
  "CatalogEntry"
end

#string_PCollectionType(t) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1741
1742
1743
1744
1745
1746
1747
1748
# File 'lib/puppet/pops/types/type_calculator.rb', line 1741

def string_PCollectionType(t)
  range = range_array_part(t.size_type)
  unless range.empty?
    "Collection[#{range.join(', ')}]"
  else
    "Collection"
  end
end

#string_PDataType(t) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1608
# File 'lib/puppet/pops/types/type_calculator.rb', line 1608

def string_PDataType(t)    ; "Data"    ; end

#string_PDefaultType(t) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1599
# File 'lib/puppet/pops/types/type_calculator.rb', line 1599

def string_PDefaultType(t) ; 'Default' ; end

#string_PEnumType(t) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1664
1665
1666
1667
# File 'lib/puppet/pops/types/type_calculator.rb', line 1664

def string_PEnumType(t)
  return "Enum" if t.values.empty?
  "Enum[" << t.values.map {|s| "'#{s}'" }.join(', ') << ']'
end

#string_PFloatType(t) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1631
1632
1633
1634
1635
1636
1637
1638
# File 'lib/puppet/pops/types/type_calculator.rb', line 1631

def string_PFloatType(t)
  range = range_array_part(t)
  unless range.empty?
    "Float[#{range.join(', ')}]"
  else
    "Float"
  end
end

#string_PHashType(t) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1765
1766
1767
1768
# File 'lib/puppet/pops/types/type_calculator.rb', line 1765

def string_PHashType(t)
  parts = [string(t.key_type), string(t.element_type)] + range_array_part(t.size_type)
  "Hash[#{parts.join(', ')}]"
end

#string_PHostClassType(t) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1776
1777
1778
1779
1780
1781
1782
# File 'lib/puppet/pops/types/type_calculator.rb', line 1776

def string_PHostClassType(t)
  if t.class_name
    "Class[#{t.class_name}]"
  else
    "Class"
  end
end

#string_PIntegerType(t) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1614
1615
1616
1617
1618
1619
1620
1621
# File 'lib/puppet/pops/types/type_calculator.rb', line 1614

def string_PIntegerType(t)
  range = range_array_part(t)
  unless range.empty?
    "Integer[#{range.join(', ')}]"
  else
    "Integer"
  end
end

#string_PNotUndefType(t) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
# File 'lib/puppet/pops/types/type_calculator.rb', line 1798

def string_PNotUndefType(t)
  contained_type = t.type
  if contained_type.nil? || contained_type.class == Puppet::Pops::Types::PAnyType
    'NotUndef'
  else
    if contained_type.is_a?(Puppet::Pops::Types::PStringType) && contained_type.values.size == 1
      "NotUndef['#{contained_type.values[0]}']"
    else
      "NotUndef[#{string(contained_type)}]"
    end
  end
end

#string_PNumericType(t) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1611
# File 'lib/puppet/pops/types/type_calculator.rb', line 1611

def string_PNumericType(t) ; "Numeric" ; end

#string_POptionalType(t) ⇒ Object



1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
# File 'lib/puppet/pops/types/type_calculator.rb', line 1811

def string_POptionalType(t)
  optional_type = t.optional_type
  if optional_type.nil?
    "Optional"
  else
    if optional_type.is_a?(Puppet::Pops::Types::PStringType) && optional_type.values.size == 1
      "Optional['#{optional_type.values[0]}']"
    else
      "Optional[#{string(optional_type)}]"
    end
  end
end

#string_PPatternType(t) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1735
1736
1737
1738
# File 'lib/puppet/pops/types/type_calculator.rb', line 1735

def string_PPatternType(t)
  return "Pattern" if t.patterns.empty?
  "Pattern[" << t.patterns.map {|s| "#{s.regexp.inspect}" }.join(', ') << ']'
end

#string_PRegexpType(t) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1641
1642
1643
# File 'lib/puppet/pops/types/type_calculator.rb', line 1641

def string_PRegexpType(t)
  t.pattern.nil? ? "Regexp" : "Regexp[#{t.regexp.inspect}]"
end

#string_PResourceType(t) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
# File 'lib/puppet/pops/types/type_calculator.rb', line 1785

def string_PResourceType(t)
  if t.type_name
    if t.title
      "#{capitalize_segments(t.type_name)}['#{t.title}']"
    else
      capitalize_segments(t.type_name)
    end
  else
    "Resource"
  end
end

#string_PRuntimeType(t) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1756
# File 'lib/puppet/pops/types/type_calculator.rb', line 1756

def string_PRuntimeType(t)   ; "Runtime[#{string(t.runtime)}, #{string(t.runtime_type_name)}]"  ; end

#string_PScalarType(t) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1605
# File 'lib/puppet/pops/types/type_calculator.rb', line 1605

def string_PScalarType(t)  ; "Scalar"  ; end

#string_PStringType(t) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1646
1647
1648
1649
1650
1651
1652
1653
1654
# File 'lib/puppet/pops/types/type_calculator.rb', line 1646

def string_PStringType(t)
  # skip values in regular output - see debug_string
  range = range_array_part(t.size_type)
  unless range.empty?
    "String[#{range.join(', ')}]"
  else
    "String"
  end
end

#string_PStructElement(t) ⇒ Object



1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
# File 'lib/puppet/pops/types/type_calculator.rb', line 1721

def string_PStructElement(t)
  k = t.key_type
  value_optional = assignable?(t.value_type, @nil_t)
  key_string =
    if k.is_a?(Types::POptionalType)
      # Output as literal String
      value_optional ? "'#{t.name}'" : string(k)
    else
      value_optional ? "NotUndef['#{t.name}']" : "'#{t.name}'"
    end
  "#{key_string}=>#{string(t.value_type)}"
end

#string_PStructType(t) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1716
1717
1718
1719
# File 'lib/puppet/pops/types/type_calculator.rb', line 1716

def string_PStructType(t)
  return "Struct" if t.elements.empty?
  "Struct[{" << t.elements.map {|element| string(element) }.join(', ') << "}]"
end

#string_PTupleType(t) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
# File 'lib/puppet/pops/types/type_calculator.rb', line 1676

def string_PTupleType(t)
  range = range_array_part(t.size_type)
  return "Tuple" if t.types.empty?
  s = "Tuple[" << t.types.map {|t2| string(t2) }.join(', ')
  unless range.empty?
    s << ", " << range.join(', ')
  end
  s << "]"
  s
end

#string_PType(t) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1576
1577
1578
1579
1580
1581
1582
# File 'lib/puppet/pops/types/type_calculator.rb', line 1576

def string_PType(t)
  if t.type.nil?
    "Type"
  else
    "Type[#{string(t.type)}]"
  end
end

#string_PUndefType(t) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1596
# File 'lib/puppet/pops/types/type_calculator.rb', line 1596

def string_PUndefType(t)     ; 'Undef'   ; end

#string_PUnitType(t) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1751
1752
1753
# File 'lib/puppet/pops/types/type_calculator.rb', line 1751

def string_PUnitType(t)
  "Unit"
end

#string_PVariantType(t) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1670
1671
1672
1673
# File 'lib/puppet/pops/types/type_calculator.rb', line 1670

def string_PVariantType(t)
  return "Variant" if t.types.empty?
  "Variant[" << t.types.map {|t2| string(t2) }.join(', ') << ']'
end

#string_String(t) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1588
# File 'lib/puppet/pops/types/type_calculator.rb', line 1588

def string_String(t)       ; t         ; end

#string_Symbol(t) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1591
# File 'lib/puppet/pops/types/type_calculator.rb', line 1591

def string_Symbol(t)       ; t.to_s    ; end

#superclasses(c) ⇒ Object

Produces the superclasses of the given class, including the class



725
726
727
728
729
730
731
732
# File 'lib/puppet/pops/types/type_calculator.rb', line 725

def superclasses(c)
  result = [c]
  while s = c.superclass
    result << s
    c = s
  end
  result
end

#tuple_entry_at(tuple_t, from, to, index) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

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



1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
# File 'lib/puppet/pops/types/type_calculator.rb', line 1231

def tuple_entry_at(tuple_t, from, to, index)
  regular = (tuple_t.types.size - 1)
  if index < regular
    tuple_t.types[index]
  elsif index < regular + to
    # in the varargs part
    tuple_t.types[-1]
  else
    nil
  end
end

#type(c) ⇒ Object

Answers ‘what is the Puppet Type corresponding to the given Ruby class’

Parameters:

  • c (Class)

    the class for which a puppet type is wanted

Raises:

  • (ArgumentError)


316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
# File 'lib/puppet/pops/types/type_calculator.rb', line 316

def type(c)
  raise ArgumentError, "Argument must be a Class" unless c.is_a? Class

  # Can't use a visitor here since we don't have an instance of the class
  case
  when c <= Integer
    type = Types::PIntegerType.new()
  when c == Float
    type = Types::PFloatType.new()
  when c == Numeric
    type = Types::PNumericType.new()
  when c == String
    type = Types::PStringType.new()
  when c == Regexp
    type = Types::PRegexpType.new()
  when c == NilClass
    type = Types::PUndefType.new()
  when c == FalseClass, c == TrueClass
    type = Types::PBooleanType.new()
  when c == Class
    type = Types::PType.new()
  when c == Array
    # Assume array of data values
    type = Types::PArrayType.new()
    type.element_type = Types::PDataType.new()
  when c == Hash
    # Assume hash with scalar keys and data values
    type = Types::PHashType.new()
    type.key_type = Types::PScalarType.new()
    type.element_type = Types::PDataType.new()
  else
    type = Types::PRuntimeType.new(:runtime => :ruby, :runtime_type_name => c.name)
  end
  type
end

#unwrap_single_variant(possible_variant) ⇒ Object



1000
1001
1002
1003
1004
1005
1006
# File 'lib/puppet/pops/types/type_calculator.rb', line 1000

def unwrap_single_variant(possible_variant)
  if possible_variant.is_a?(Types::PVariantType) && possible_variant.types.size == 1
    possible_variant.types[0]
  else
    possible_variant
  end
end