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
34 def self.asserted_iterable(my_caller, obj, infer_elements = false)
35   iter = self.on(obj, nil, infer_elements)
36   raise ArgumentError, "#{my_caller.class}(): wrong argument type (#{obj.class}; is not Iterable." if iter.nil?
37   iter
38 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
 62 def self.on(o, element_type = nil, infer_elements = true)
 63   case o
 64   when IteratorProducer
 65     o.iterator
 66   when Iterable
 67     o
 68   when String
 69     Iterator.new(PStringType.new(PIntegerType.new(1, 1)), o.each_char)
 70   when Array
 71     if o.empty?
 72       Iterator.new(PUnitType::DEFAULT, o.each)
 73     else
 74       if element_type.nil? && infer_elements
 75         tc = TypeCalculator.singleton
 76         element_type = PVariantType.maybe_create(o.map {|e| tc.infer_set(e) })
 77       end
 78       Iterator.new(element_type, o.each)
 79     end
 80   when Hash
 81     # Each element is a two element [key, value] tuple.
 82     if o.empty?
 83       HashIterator.new(PHashType::DEFAULT_KEY_PAIR_TUPLE, o.each)
 84     else
 85       if element_type.nil? && infer_elements
 86         tc = TypeCalculator.singleton
 87         element_type = PTupleType.new([
 88           PVariantType.maybe_create(o.keys.map {|e| tc.infer_set(e) }),
 89           PVariantType.maybe_create(o.values.map {|e| tc.infer_set(e) })], PHashType::KEY_PAIR_TUPLE_SIZE)
 90       end
 91       HashIterator.new(element_type, o.each_pair)
 92     end
 93   when Integer
 94     if o == 0
 95       Iterator.new(PUnitType::DEFAULT, o.times)
 96     elsif o > 0
 97       IntegerRangeIterator.new(PIntegerType.new(0, o - 1))
 98     else
 99       nil
100     end
101   when PIntegerType
102     # a finite range will always produce at least one element since it's inclusive
103     o.finite_range? ? IntegerRangeIterator.new(o) : nil
104   when PEnumType
105     Iterator.new(o, o.values.each)
106   when PTypeAliasType
107     on(o.resolved_type)
108   when Range
109     min = o.min
110     max = o.max
111     if min.is_a?(Integer) && max.is_a?(Integer) && max >= min
112       IntegerRangeIterator.new(PIntegerType.new(min, max))
113     elsif min.is_a?(String) && max.is_a?(String) && max >= min
114       # A generalized element type where only the size is inferred is used here since inferring the full
115       # range might waste a lot of memory.
116       if min.length < max.length
117         shortest = min
118         longest = max
119       else
120         shortest = max
121         longest = min
122       end
123       Iterator.new(PStringType.new(PIntegerType.new(shortest.length, longest.length)), o.each)
124     else
125       # Unsupported range. It's either descending or nonsensical for other reasons (float, mixed types, etc.)
126       nil
127     end
128   else
129     # Not supported. We cannot determine the element type
130     nil
131   end
132 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
138 def self.unbounded?(object)
139   case object
140   when Iterable
141     object.unbounded?
142   when String,Integer,Array,Hash,Enumerator,PIntegerType,PEnumType,Dir
143     false
144   else
145     TypeAsserter.assert_instance_of('', PIterableType::DEFAULT, object, false)
146     !object.respond_to?(:size)
147   end
148 end

Public Instance Methods

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