Update stdlib and concat to 6.1.0 both
[mirror/dsa-puppet.git] / 3rdparty / modules / stdlib / lib / puppet / parser / functions / values_at.rb
1 #
2 # values_at.rb
3 #
4 module Puppet::Parser::Functions
5   newfunction(:values_at, :type => :rvalue, :doc => <<-DOC
6     @summary
7       Finds value inside an array based on location.
8
9     The first argument is the array you want to analyze, and the second element can
10     be a combination of:
11
12     * A single numeric index
13     * A range in the form of 'start-stop' (eg. 4-9)
14     * An array combining the above
15
16     @return
17       an array of values identified by location
18
19     @example **Usage**
20
21       values_at(['a','b','c'], 2)
22       Would return ['c']
23
24       values_at(['a','b','c'], ["0-1"])
25       Would return ['a','b']
26
27       values_at(['a','b','c','d','e'], [0, "2-3"])
28       Would return ['a','c','d']
29
30     > *Note:*
31     Since Puppet 4.0.0 it is possible to slice an array with index and count directly in the language.
32     A negative value is taken to be "from the end" of the array:
33
34     `['a', 'b', 'c', 'd'][1, 2]`   results in `['b', 'c']`
35     `['a', 'b', 'c', 'd'][2, -1]`  results in `['c', 'd']`
36     `['a', 'b', 'c', 'd'][1, -2]`  results in `['b', 'c']`
37
38     DOC
39              ) do |arguments|
40
41     raise(Puppet::ParseError, "values_at(): Wrong number of arguments given (#{arguments.size} for 2)") if arguments.size < 2
42
43     array = arguments.shift
44
45     unless array.is_a?(Array)
46       raise(Puppet::ParseError, 'values_at(): Requires array to work with')
47     end
48
49     indices = [arguments.shift].flatten # Get them all ... Pokemon ...
50
51     if !indices || indices.empty?
52       raise(Puppet::ParseError, 'values_at(): You must provide at least one positive index to collect')
53     end
54
55     indices_list = []
56
57     indices.each do |i|
58       i = i.to_s
59       m = i.match(%r{^(\d+)(\.\.\.?|\-)(\d+)$})
60       if m
61         start = m[1].to_i
62         stop  = m[3].to_i
63
64         type = m[2]
65
66         raise(Puppet::ParseError, 'values_at(): Stop index in given indices range is smaller than the start index') if start > stop
67         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?
68
69         range = case type
70                 when %r{^(\.\.|\-)$} then (start..stop)
71                 when %r{^(\.\.\.)$}  then (start...stop) # Exclusive of last element ...
72                 end
73
74         range.each { |i| indices_list << i.to_i } # rubocop:disable Lint/ShadowingOuterLocalVariable : Value is meant to be shadowed
75       else
76         # Only positive numbers allowed in this case ...
77         unless i =~ %r{^\d+$}
78           raise(Puppet::ParseError, 'values_at(): Unknown format of given index')
79         end
80
81         # In Puppet numbers are often string-encoded ...
82         i = i.to_i
83
84         if i > array.size - 1 # Same story.  First element is at index 0 ...
85           raise(Puppet::ParseError, 'values_at(): Given index exceeds array size')
86         end
87
88         indices_list << i
89       end
90     end
91
92     # We remove nil values as they make no sense in Puppet DSL ...
93     result = indices_list.map { |i| array[i] }.compact
94
95     return result
96   end
97 end
98
99 # vim: set ts=2 sw=2 et :