Merge remote-tracking branch 'pr/56' into pull-56
[puppet_stdlib.git] / lib / puppet / parser / functions / range.rb
1 #
2 # range.rb
3 #
4
5 # TODO(Krzysztof Wilczynski): We probably need to approach numeric values differently ...
6
7 module Puppet::Parser::Functions
8   newfunction(:range, :type => :rvalue, :doc => <<-EOS
9 When given range in the form of (start, stop) it will extrapolate a range as
10 an array.
11
12 *Examples:*
13
14     range("0", "9")
15
16 Will return: [0,1,2,3,4,5,6,7,8,9]
17
18     range("00", "09")
19
20 Will return: [0,1,2,3,4,5,6,7,8,9] (Zero padded strings are converted to
21 integers automatically)
22
23     range("a", "c")
24
25 Will return: ["a","b","c"]
26
27     range("host01", "host10")
28
29 Will return: ["host01", "host02", ..., "host09", "host10"]
30
31 Passing a third argument will cause the generated range to step by that 
32 interval, e.g.
33
34     range("0", "9", "2")
35
36 Will return: [0,2,4,6,8]
37     EOS
38   ) do |arguments|
39
40     # We support more than one argument but at least one is mandatory ...
41     raise(Puppet::ParseError, "range(): Wrong number of " +
42       "arguments given (#{arguments.size} for 1)") if arguments.size < 1
43
44     if arguments.size > 1
45       start = arguments[0]
46       stop  = arguments[1]
47       step  = arguments[2].nil? ? 1 : arguments[2].to_i.abs
48
49       type = '..' # We select simplest type for Range available in Ruby ...
50
51     elsif arguments.size > 0
52       value = arguments[0]
53
54       if m = value.match(/^(\w+)(\.\.\.?|\-)(\w+)$/)
55         start = m[1]
56         stop  = m[3]
57
58         type = m[2]
59
60       elsif value.match(/^.+$/)
61         raise(Puppet::ParseError, 'range(): Unable to compute range ' +
62           'from the value given')
63       else
64         raise(Puppet::ParseError, 'range(): Unknown format of range given')
65       end
66     end
67
68       # Check whether we have integer value if so then make it so ...
69       if start.match(/^\d+$/)
70         start = start.to_i
71         stop  = stop.to_i
72       else
73         start = start.to_s
74         stop  = stop.to_s
75       end
76
77       range = case type
78         when /^(\.\.|\-)$/ then (start .. stop)
79         when /^(\.\.\.)$/  then (start ... stop) # Exclusive of last element ...
80       end
81
82       result = range.step(step).collect { |i| i } # Get them all ... Pokemon ...
83
84     return result
85   end
86 end
87
88 # vim: set ts=2 sw=2 et :