module Puppet::Pops::Types::Iterable

The runtime Iterable type for an Iterable

Public Class Methods

asserted_iterable(my_caller, obj, infer_elements = false) click to toggle source

Produces an `Iterable` for one of the following types with the following characterstics:

`String` - yields each character in the string `Array` - yields each element in the array `Hash` - yields each key/value pair as a two element array `Integer` - when positive, yields each value from zero to the given number `PIntegerType` - yields each element from min to max (inclusive) provided min < max and neither is unbounded. `PEnumtype` - yields each possible value of the enum. `Range` - yields an iterator for all elements in the range provided that the range start and end

are both integers or both strings and start is less than end using natural ordering.

`Dir` - yields each name in the directory

An `ArgumentError` is raised for all other objects.

@param my_caller [Object] The calling object to reference in errors @param obj [Object] The object to produce an `Iterable` for @param infer_elements [Boolean] Whether or not to recursively infer all elements of obj. Optional

@return [Iterable,nil] The produced `Iterable` @raise [ArgumentError] In case an `Iterable` cannot be produced @api public

   # File lib/puppet/pops/types/iterable.rb
33 def self.asserted_iterable(my_caller, obj, infer_elements = false)
34   iter = self.on(obj, nil, infer_elements)
35   raise ArgumentError, "#{my_caller.class}(): wrong argument type (#{obj.class}; is not Iterable." if iter.nil?
36   iter
37 end
on(o, element_type = nil, infer_elements = true) click to toggle source

Produces an `Iterable` for one of the following types with the following characteristics:

`String` - yields each character in the string `Array` - yields each element in the array `Hash` - yields each key/value pair as a two element array `Integer` - when positive, yields each value from zero to the given number `PIntegerType` - yields each element from min to max (inclusive) provided min < max and neither is unbounded. `PEnumtype` - yields each possible value of the enum. `Range` - yields an iterator for all elements in the range provided that the range start and end

are both integers or both strings and start is less than end using natural ordering.

`Dir` - yields each name in the directory

The value `nil` is returned for all other objects.

@param o [Object] The object to produce an `Iterable` for @param element_type [PAnyType] the element type for the iterator. Optional @param infer_elements [Boolean] if element_type is nil, whether or not to recursively

infer types for the entire collection. Optional

@return [Iterable,nil] The produced `Iterable` or `nil` if it couldn't be produced

@api public

    # File lib/puppet/pops/types/iterable.rb
 61 def self.on(o, element_type = nil, infer_elements = true)
 62   case o
 63   when IteratorProducer
 64     o.iterator
 65   when Iterable
 66     o
 67   when String
 68     Iterator.new(PStringType.new(PIntegerType.new(1, 1)), o.each_char)
 69   when Array
 70     if o.empty?
 71       Iterator.new(PUnitType::DEFAULT, o.each)
 72     else
 73       if element_type.nil? && infer_elements
 74         tc = TypeCalculator.singleton
 75         element_type = PVariantType.maybe_create(o.map {|e| tc.infer_set(e) })
 76       end
 77       Iterator.new(element_type, o.each)
 78     end
 79   when Hash
 80     # Each element is a two element [key, value] tuple.
 81     if o.empty?
 82       HashIterator.new(PHashType::DEFAULT_KEY_PAIR_TUPLE, o.each)
 83     else
 84       if element_type.nil? && infer_elements
 85         tc = TypeCalculator.singleton
 86         element_type = PTupleType.new([
 87           PVariantType.maybe_create(o.keys.map {|e| tc.infer_set(e) }),
 88           PVariantType.maybe_create(o.values.map {|e| tc.infer_set(e) })], PHashType::KEY_PAIR_TUPLE_SIZE)
 89       end
 90       HashIterator.new(element_type, o.each_pair)
 91     end
 92   when Integer
 93     if o == 0
 94       Iterator.new(PUnitType::DEFAULT, o.times)
 95     elsif o > 0
 96       IntegerRangeIterator.new(PIntegerType.new(0, o - 1))
 97     else
 98       nil
 99     end
100   when PIntegerType
101     # a finite range will always produce at least one element since it's inclusive
102     o.finite_range? ? IntegerRangeIterator.new(o) : nil
103   when PEnumType
104     Iterator.new(o, o.values.each)
105   when PTypeAliasType
106     on(o.resolved_type)
107   when Range
108     min = o.min
109     max = o.max
110     if min.is_a?(Integer) && max.is_a?(Integer) && max >= min
111       IntegerRangeIterator.new(PIntegerType.new(min, max))
112     elsif min.is_a?(String) && max.is_a?(String) && max >= min
113       # A generalized element type where only the size is inferred is used here since inferring the full
114       # range might waste a lot of memory.
115       if min.length < max.length
116         shortest = min
117         longest = max
118       else
119         shortest = max
120         longest = min
121       end
122       Iterator.new(PStringType.new(PIntegerType.new(shortest.length, longest.length)), o.each)
123     else
124       # Unsupported range. It's either descending or nonsensical for other reasons (float, mixed types, etc.)
125       nil
126     end
127   else
128     # Not supported. We cannot determine the element type
129     nil
130   end
131 end
unbounded?(object) click to toggle source

Answers the question if there is an end to the iteration. Puppet does not currently provide any unbounded iterables.

@return [Boolean] `true` if the iteration is unbounded

    # File lib/puppet/pops/types/iterable.rb
137 def self.unbounded?(object)
138   case object
139   when Iterable
140     object.unbounded?
141   when String,Integer,Array,Hash,Enumerator,PIntegerType,PEnumType,Dir
142     false
143   else
144     TypeAsserter.assert_instance_of('', PIterableType::DEFAULT, object, false)
145     !object.respond_to?(:size)
146   end
147 end

Public Instance Methods

each(&block) click to toggle source
    # File lib/puppet/pops/types/iterable.rb
149 def each(&block)
150   step(1, &block)
151 end
element_type() click to toggle source
    # File lib/puppet/pops/types/iterable.rb
153 def element_type
154   PAnyType::DEFAULT
155 end
hash_style?() click to toggle source
    # File lib/puppet/pops/types/iterable.rb
174 def hash_style?
175   false
176 end
reverse_each(&block) click to toggle source
    # File lib/puppet/pops/types/iterable.rb
157 def reverse_each(&block)
158   # Default implementation cannot propagate reverse_each to a new enumerator so chained
159   # calls must put reverse_each last.
160   raise ArgumentError, 'reverse_each() is not implemented'
161 end
step(step, &block) click to toggle source
    # File lib/puppet/pops/types/iterable.rb
163 def step(step, &block)
164   # Default implementation cannot propagate step to a new enumerator so chained
165   # calls must put stepping last.
166   raise ArgumentError, 'step() is not implemented'
167 end
to_a() click to toggle source
Calls superclass method
    # File lib/puppet/pops/types/iterable.rb
169 def to_a
170   raise Puppet::Error, 'Attempt to create an Array from an unbounded Iterable' if unbounded?
171   super
172 end
unbounded?() click to toggle source
    # File lib/puppet/pops/types/iterable.rb
178 def unbounded?
179   true
180 end