Skip to content

Commit f0559d5

Browse files
author
Maksym Melnychok
committed
Add dig() function
Deprecates #try_get_value()
1 parent 990e1d7 commit f0559d5

5 files changed

Lines changed: 112 additions & 50 deletions

File tree

README.markdown

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,42 @@ Deletes all instances of the undef value from an array or hash. For example, `$h
254254

255255
Returns the difference between two arrays. The returned array is a copy of the original array, removing any items that also appear in the second array. For example, `difference(["a","b","c"],["b","c","d"])` returns ["a"]. *Type*: rvalue.
256256

257+
#### `dig`
258+
259+
*Type*: rvalue.
260+
261+
Retrieves a value within multiple layers of hashes and arrays via an array of keys containing a path. The function goes through the structure by each path component and tries to return the value at the end of the path.
262+
263+
In addition to the required path argument, the function accepts the default argument. It is returned if the path is not correct, if no value was found, or if any other error has occurred.
264+
265+
~~~ruby
266+
$data = {
267+
'a' => {
268+
'b' => [
269+
'b1',
270+
'b2',
271+
'b3',
272+
]
273+
}
274+
}
275+
276+
$value = dig($data, ['a', 'b', 2])
277+
# $value = 'b3'
278+
279+
# with all possible options
280+
$value = dig($data, ['a', 'b', 2], 'not_found')
281+
# $value = 'b3'
282+
283+
# using the default value
284+
$value = dig($data, ['a', 'b', 'c', 'd'], 'not_found')
285+
# $value = 'not_found'
286+
~~~
287+
288+
1. **$data** The data structure we are working with.
289+
2. **['a', 'b', 2]** The path array.
290+
3. **'not_found'** The default value. It will be returned if nothing is found.
291+
(optional, defaults to *undef*)
292+
257293
#### `dirname`
258294

259295
Returns the `dirname` of a path. For example, `dirname('/path/to/a/file.ext')` returns '/path/to/a'. *Type*: rvalue.
@@ -806,6 +842,8 @@ Converts the argument into bytes, for example "4 kB" becomes "4096". Takes a sin
806842

807843
*Type*: rvalue.
808844

845+
DEPRECATED: replaced by `dig()`.
846+
809847
Retrieves a value within multiple layers of hashes and arrays via a string containing a path. The path is a string of hash keys or array indexes starting with zero, separated by the path separator character (default "/"). The function goes through the structure by each path component and tries to return the value at the end of the path.
810848

811849
In addition to the required path argument, the function accepts the default argument. It is returned if the path is not correct, if no value was found, or if any other error has occurred. The last argument can set the path separator character.

lib/puppet/parser/functions/dig.rb

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#
2+
# dig.rb
3+
#
4+
5+
module Puppet::Parser::Functions
6+
newfunction(:dig, :type => :rvalue, :doc => <<-EOS
7+
Looks up into a complex structure of arrays and hashes and returns nil
8+
or the default value if nothing was found.
9+
10+
Path is an array of keys to be looked up in data argument. The function
11+
will go down the structure and try to extract the required value.
12+
13+
$data = {
14+
'a' => {
15+
'b' => [
16+
'b1',
17+
'b2',
18+
'b3' ]}}
19+
20+
$value = try_get_value($data, ['a', 'b', '2'], 'not_found')
21+
=> $value = 'b3'
22+
23+
a -> first hash key
24+
b -> second hash key
25+
2 -> array index starting with 0
26+
27+
not_found -> (optional) will be returned if there is no value or the path
28+
did not match. Defaults to nil.
29+
30+
In addition to the required "path" argument, "dig" accepts default
31+
argument. It will be returned if no value was found or a path component is
32+
missing. And the fourth argument can set a variable path separator.
33+
EOS
34+
) do |arguments|
35+
# Two arguments are required
36+
raise(Puppet::ParseError, "dig(): Wrong number of arguments " +
37+
"given (#{arguments.size} for at least 2)") if arguments.size < 2
38+
39+
data, path, default = *arguments
40+
41+
if !(data.is_a?(Hash) || data.is_a?(Array))
42+
raise(Puppet::ParseError, "dig(): first argument must be a hash or an array, " <<
43+
"given #{data.class.name}")
44+
end
45+
46+
unless path.is_a? Array
47+
raise(Puppet::ParseError, "dig(): second argument must be an array, " <<
48+
"given #{path.class.name}")
49+
end
50+
51+
value = path.reduce(data) { |h, k| (h.is_a?(Hash) || h.is_a?(Array)) ? h[k] : break }
52+
value.nil? ? default : value
53+
end
54+
end
55+
56+
# vim: set ts=2 sw=2 et :

lib/puppet/parser/functions/try_get_value.rb

Lines changed: 5 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ module Puppet::Parser::Functions
44
:type => :rvalue,
55
:arity => -2,
66
:doc => <<-eos
7+
DEPRECATED: this function is deprecated, please use dig() instead.
8+
79
Looks up into a complex structure of arrays and hashes and returns a value
810
or the default value if nothing was found.
911
@@ -35,43 +37,12 @@ module Puppet::Parser::Functions
3537
missing. And the fourth argument can set a variable path separator.
3638
eos
3739
) do |args|
38-
path_lookup = lambda do |data, path, default|
39-
debug "Try_get_value: #{path.inspect} from: #{data.inspect}"
40-
if data.nil?
41-
debug "Try_get_value: no data, return default: #{default.inspect}"
42-
break default
43-
end
44-
unless path.is_a? Array
45-
debug "Try_get_value: wrong path, return default: #{default.inspect}"
46-
break default
47-
end
48-
unless path.any?
49-
debug "Try_get_value: value found, return data: #{data.inspect}"
50-
break data
51-
end
52-
unless data.is_a? Hash or data.is_a? Array
53-
debug "Try_get_value: incorrect data, return default: #{default.inspect}"
54-
break default
55-
end
56-
57-
key = path.shift
58-
if data.is_a? Array
59-
begin
60-
key = Integer key
61-
rescue ArgumentError
62-
debug "Try_get_value: non-numeric path for an array, return default: #{default.inspect}"
63-
break default
64-
end
65-
end
66-
path_lookup.call data[key], path, default
67-
end
68-
40+
warning("try_get_value() DEPRECATED: this function is deprecated, please use dig() instead.")
6941
data = args[0]
7042
path = args[1] || ''
7143
default = args[2]
7244
separator = args[3] || '/'
73-
74-
path = path.split separator
75-
path_lookup.call data, path, default
45+
path = path.split(separator).map{ |key| key =~ /^\d+$/ ? key.to_i : key }
46+
function_dig([data, path, default])
7647
end
7748
end

spec/functions/dig_spec.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
require 'spec_helper'
2+
3+
describe 'dig' do
4+
it { is_expected.to run.with_params().and_raise_error(Puppet::ParseError) }
5+
it { is_expected.to run.with_params('bad', []).and_raise_error(Puppet::ParseError) }
6+
it { is_expected.to run.with_params({}, 'bad').and_raise_error(Puppet::ParseError) }
7+
8+
it { is_expected.to run.with_params({}, []).and_return({}) }
9+
it { is_expected.to run.with_params({"a" => "b"}, ["a"]).and_return("b") }
10+
it { is_expected.to run.with_params({"a" => {"b" => "c"}}, ["a", "b"]).and_return("c") }
11+
it { is_expected.to run.with_params({}, ["a", "b"], "d").and_return("d") }
12+
it { is_expected.to run.with_params({"a" => false}, ["a"]).and_return(false) }
13+
end

spec/functions/try_get_value_spec.rb

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -27,22 +27,6 @@
2727
it 'should exist' do
2828
is_expected.not_to eq(nil)
2929
end
30-
31-
it 'should be able to return a single value' do
32-
is_expected.to run.with_params('test').and_return('test')
33-
end
34-
35-
it 'should use the default value if data is a single value and path is present' do
36-
is_expected.to run.with_params('test', 'path', 'default').and_return('default')
37-
end
38-
39-
it 'should return default if there is no data' do
40-
is_expected.to run.with_params(nil, nil, 'default').and_return('default')
41-
end
42-
43-
it 'should be able to use data structures as default values' do
44-
is_expected.to run.with_params('test', 'path', data).and_return(data)
45-
end
4630
end
4731

4832
context 'structure values' do

0 commit comments

Comments
 (0)