Skip to content
This repository was archived by the owner on Dec 11, 2024. It is now read-only.

Commit 8731898

Browse files
committed
added support to fetch nested values in many formats
1 parent 47c40f0 commit 8731898

File tree

2 files changed

+73
-17
lines changed

2 files changed

+73
-17
lines changed

lib/recollect/utility.rb

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,31 @@
22

33
module Recollect
44
module Utility
5+
module Keys
6+
extend self
7+
8+
DELIMITER_REGEX = /\[|\]|\./
9+
10+
def to_ary(key)
11+
return [] if key.empty?
12+
13+
key.to_s.split(DELIMITER_REGEX).reject(&:empty?)
14+
end
15+
alias [] to_ary
16+
17+
def to_dig(key)
18+
enforce_level = ->(level) do
19+
if level.is_a?(Integer) || level.match?(/^\d$/)
20+
level.to_i
21+
else
22+
level.to_sym
23+
end
24+
end
25+
26+
Keys[key].map(&enforce_level)
27+
end
28+
end
29+
530
# ### Utility::TryFetchOrBlank
631
# `fetch value into hash, like Lodash.get`
732
#
@@ -18,19 +43,21 @@ module Utility
1843
# ````
1944
# hash = { a: 1, b: { c: 2 }, d: [{ e: 3 }] }
2045
# Utility::TryFetchOrBlank.(hash, 'd.0.e')
21-
# ````
22-
TryFetchOrBlank = lambda do |data, *keys|
23-
keys.reduce(data) do |memo, key|
24-
symbolized_keys = key.to_s.split('.').map do |k|
25-
if k.is_a?(Numeric) || k.match?(/\d/)
26-
k.to_i
27-
else
28-
k.to_sym
29-
end
30-
end
3146

32-
memo.dig(*symbolized_keys)
47+
# hash = { a: 1, b: { c: 2 }, d: [{ e: 3 }] }
48+
# Utility::TryFetchOrBlank.(hash, 'd[0]e')
49+
50+
# hash = { a: 1, b: { c: 2 }, d: [{ e: 3 }] }
51+
# Utility::TryFetchOrBlank.(hash, 'd.[0].e')
52+
# ````
53+
TryFetchOrBlank = ->(data, *keys) do
54+
reducer = ->(memo, key) do
55+
memo.dig(*Keys.to_dig(key))
56+
rescue StandardError
57+
nil
3358
end
59+
60+
keys.reduce(data, &reducer)
3461
end
3562
end
3663
end

spec/lib/recollect/utility_spec.rb

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,44 @@
3131
end
3232

3333
context 'Array' do
34-
it 'check array levels' do
35-
hash = { a: 1, b: { c: 2 }, d: ['1'] }
36-
expect(described_class.call(hash, 'd.0')).to eq('1')
34+
subject(:result) { described_class.call(hash, iteratee) }
35+
36+
context 'iteratee one level' do
37+
let(:hash) { { a: 1, b: { c: 2 }, d: ['1'] } }
38+
let(:iteratee) { 'd.0' }
39+
40+
it { expect(result).to eq('1') }
41+
end
42+
43+
context 'iteratee one level' do
44+
let(:hash) { { a: 1, b: { c: 2 }, d: [{ e: 3 }] } }
45+
let(:iteratee) { 'd.0.e' }
46+
47+
it { expect(result).to eq(3) }
3748
end
3849

39-
it 'check array + hash levels' do
40-
hash = { a: 1, b: { c: 2 }, d: [{ e: 3 }] }
50+
context 'iteratee nested levels on the complex hash' do
51+
let(:hash) do
52+
{
53+
a: 1,
54+
b: { c: 2 },
55+
d: [
56+
{
57+
e: [
58+
{ e1: 1 },
59+
{ e2: 2 },
60+
{ e3: 3 }
61+
]
62+
}
63+
]
64+
}
65+
end
4166

42-
expect(described_class[hash, 'd.0.e']).to eq(3)
67+
it { expect(described_class[hash, 'd.0.e.2.e3']).to eq(3) }
68+
it { expect(described_class[hash, 'd.0.e.[2].e3']).to eq(3) }
69+
it { expect(described_class[hash, 'd.0.e[2].e3']).to eq(3) }
70+
it { expect(described_class[hash, 'd[0]e.2.e3']).to eq(3) }
71+
it { expect(described_class[hash, 'd.[0].e[1]e2']).to eq(2) }
4372
end
4473
end
4574
end

0 commit comments

Comments
 (0)