Puppet Function: values_at

Defined in:
lib/puppet/parser/functions/values_at.rb
Function type:
Ruby 3.x API

Overview

values_at()Any

Finds value inside an array based on location.

The first argument is the array you want to analyze, and the second element can be a combination of:

  • A single numeric index

  • A range in the form of ‘start-stop’ (eg. 4-9)

  • An array combining the above

Examples:

values_at(['a','b','c'], 2)

Would return [‘c’].

values_at(['a','b','c'], ["0-1"])

Would return [‘a’,‘b’].

values_at(['a','b','c','d','e'], [0, "2-3"])

Would return [‘a’,‘c’,‘d’].

Returns:

  • (Any)


5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/puppet/parser/functions/values_at.rb', line 5

newfunction(:values_at, :type => :rvalue, :doc => <<-DOC
  Finds value inside an array based on location.

  The first argument is the array you want to analyze, and the second element can
  be a combination of:

  * A single numeric index
  * A range in the form of 'start-stop' (eg. 4-9)
  * An array combining the above

  *Examples*:

      values_at(['a','b','c'], 2)

  Would return ['c'].

      values_at(['a','b','c'], ["0-1"])

  Would return ['a','b'].

      values_at(['a','b','c','d','e'], [0, "2-3"])

  Would return ['a','c','d'].
  DOC
           ) do |arguments|

  raise(Puppet::ParseError, "values_at(): Wrong number of arguments given (#{arguments.size} for 2)") if arguments.size < 2

  array = arguments.shift

  unless array.is_a?(Array)
    raise(Puppet::ParseError, 'values_at(): Requires array to work with')
  end

  indices = [arguments.shift].flatten # Get them all ... Pokemon ...

  if !indices || indices.empty?
    raise(Puppet::ParseError, 'values_at(): You must provide at least one positive index to collect')
  end

  indices_list = []

  indices.each do |i|
    i = i.to_s
    m = i.match(%r{^(\d+)(\.\.\.?|\-)(\d+)$})
    if m
      start = m[1].to_i
      stop  = m[3].to_i

      type = m[2]

      raise(Puppet::ParseError, 'values_at(): Stop index in given indices range is smaller than the start index') if start > stop
      raise(Puppet::ParseError, 'values_at(): Stop index in given indices range exceeds array size') if stop > array.size - 1 # First element is at index 0 is it not?

      range = case type
              when %r{^(\.\.|\-)$} then (start..stop)
              when %r{^(\.\.\.)$}  then (start...stop) # Exclusive of last element ...
              end

      range.each { |i| indices_list << i.to_i } # rubocop:disable Lint/ShadowingOuterLocalVariable : Value is meant to be shadowed
    else
      # Only positive numbers allowed in this case ...
      unless i =~ %r{^\d+$}
        raise(Puppet::ParseError, 'values_at(): Unknown format of given index')
      end

      # In Puppet numbers are often string-encoded ...
      i = i.to_i

      if i > array.size - 1 # Same story.  First element is at index 0 ...
        raise(Puppet::ParseError, 'values_at(): Given index exceeds array size')
      end

      indices_list << i
    end
  end

  # We remove nil values as they make no sense in Puppet DSL ...
  result = indices_list.map { |i| array[i] }.compact

  return result
end