Skip to content

Commit

Permalink
Merge pull request #3 from dvla/feature/EPB-11376
Browse files Browse the repository at this point in the history
EPB-11376 refactor deep_find and deep_find_parent logic methods
  • Loading branch information
p-sqr authored Oct 1, 2024
2 parents d293d4b + 0d9236e commit d92d848
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 18 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/push_to_branch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
ruby-version: ['2.7', '3.0', '3.1', head]
ruby-version: ['2.7', '3.0', '3.1', '3.2', head]

steps:
- uses: actions/checkout@v3
Expand Down
16 changes: 10 additions & 6 deletions lib/hash_miner/hash.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class Hash
#
# @return [Boolean] whether the key was found
def deep_contains?(key:, hash: self)
return nil unless hash.is_a? Hash
return false unless hash.is_a? Hash
return true if hash.include? key

hash.filter_map do |_k, v|
Expand Down Expand Up @@ -245,37 +245,41 @@ def deep_remove_logic_parent(hash:, key:, parent:)
end

def deep_find_logic(hash:, key:)
hash.filter_map do |k, v|
results = hash.map do |k, v|
if k.eql? key
v
elsif v.is_a?(Hash)
deep_find_logic(hash: v, key: key)
elsif v.is_a?(Array)
[v.filter_map do |item|
[v.map do |item|
deep_find_logic(hash: item, key: key) if item.is_a?(Hash) && item.deep_contains?(key: key)
end]
end
end.flatten

results.all?(nil) ? results.uniq : results.compact
end

def deep_find_parent_logic(hash:, key:, parent:)
hash.filter_map do |k, v|
results = hash.map do |k, v|
if (parent.is_a?(Array) && parent.include?(k)) || parent.eql?(k)
case v
when Hash
deep_find_logic(key: key, hash: v)
when Array
[v.filter_map do |item|
[v.map do |item|
deep_find_logic(key: key, hash: item) if item.is_a?(Hash) && item.deep_contains?(key: key)
end]
end
elsif v.is_a?(Hash) && v.deep_contains?(key: key)
deep_find_parent_logic(hash: v, key: key, parent: parent)
elsif v.is_a?(Array)
[v.filter_map do |item|
[v.map do |item|
deep_find_parent_logic(hash: item, key: key, parent: parent) if item.is_a?(Hash) && item.deep_contains?(key: key)
end]
end
end.flatten

results.all?(nil) ? results.uniq : results.compact
end
end
2 changes: 1 addition & 1 deletion lib/hash_miner/version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# frozen_string_literal: true

module HashMiner
VERSION = '1.1.1'
VERSION = '1.1.2'
end
34 changes: 24 additions & 10 deletions spec/hash_miner_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@

RSpec.describe HashMiner do
before(:example) do
@nasty_hash = { my: { super: { duper: { deeply: 'nested hash',
is: [{ duper: 'gross', random: nil }, 'a', 1, nil] } },
hey: { duper: :a, blah: '', foo: [nil] },
deeply: [{ nested: 'hash' }] } }
@nasty_hash = { my:
{ super:
{ duper:
{ deeply: 'nested hash', is: [{ duper: 'gross', random: nil }, 'a', 1, nil] } },
hey: { duper: :a, blah: '', foo: [nil] },
test: nil,
not_true: { my_false_key: false },
deeply: [{ nested: 'hash' }] },
more_deeplyer: { test: nil } }
end

it 'has a version number' do
Expand All @@ -15,26 +20,28 @@
context ' deep_contains?' do
it 'returns true when key found' do
expect(@nasty_hash.deep_contains?(key: :foo)).to be true
expect(@nasty_hash.deep_contains?(key: :my_false_key)).to be true
end
it 'returns false when key found' do
it 'returns false when key not found' do
expect(@nasty_hash.deep_contains?(key: [:foo])).to be false
expect(@nasty_hash.deep_contains?(key: 'foo')).to be false
expect(@nasty_hash.deep_contains?(key: nil)).to be false
end

it 'returns nil when not a Hash object' do
expect(@nasty_hash.deep_contains?(key: nil, hash: [])).to be nil
expect(@nasty_hash.deep_contains?(key: nil, hash: 'a')).to be nil
it 'returns false when not a Hash object' do
expect(@nasty_hash.deep_contains?(key: nil, hash: [])).to be false
expect(@nasty_hash.deep_contains?(key: nil, hash: 'a')).to be false
end
end

context 'deep_count' do
it 'returns the count when key found' do
expect(@nasty_hash.deep_count(key: :foo)).to eq 1
expect(@nasty_hash.deep_count(key: :duper)).to eq 3
expect(@nasty_hash.deep_count(key: :my_false_key)).to eq 1
end

it 'returns 0 when key found' do
it 'returns 0 when key not found' do
expect(@nasty_hash.deep_count(key: [:foo])).to eq 0
expect(@nasty_hash.deep_count(key: 'foo')).to eq 0
expect(@nasty_hash.deep_count(key: nil)).to eq 0
Expand All @@ -55,12 +62,15 @@
])
expect(@nasty_hash.deep_find(key: :deeply)).to eq(['nested hash', { nested: 'hash' }])
expect(@nasty_hash.deep_find(key: :nested)).to eq(['hash'])
expect(@nasty_hash.deep_find(key: :not_true)).to eq([{ my_false_key: false }])
expect(@nasty_hash.deep_find(key: :my_false_key)).to eq([false])
end

it 'returns nil when key not found' do
expect(@nasty_hash.deep_find(key: [:foo])).to be nil
expect(@nasty_hash.deep_find(key: 'foo')).to be nil
expect(@nasty_hash.deep_find(key: nil)).to be nil
expect(@nasty_hash.deep_find(key: 'does_not_exist')).to be nil
end

it 'returns nil when not a Hash object' do
Expand All @@ -71,11 +81,14 @@
it 'can be scoped with a parent key' do
expect(@nasty_hash.deep_find(key: :duper, parent: :hey)).to eq([:a])
expect(@nasty_hash.deep_find(key: :duper, parent: [:hey])).to eq([:a])
expect(@nasty_hash.deep_find(key: :my_false_key, parent: :not_true)).to eq([false])
expect(@nasty_hash.deep_find(key: :duper,
parent: %i[hey
super])).to eq([
{ deeply: 'nested hash',
is: [{ duper: 'gross', random: nil }, 'a', 1, nil] }, :a
is: [
{ duper: 'gross', random: nil }, 'a', 1, nil
] }, :a
])
end

Expand All @@ -100,6 +113,7 @@
is: [{ duper: 'gross' }, 'a', 1,
nil] } },
hey: { duper: :a, foo: [nil] },
not_true: { my_false_key: false },
deeply: [{ nested: 'hash' }] } })
end
end
Expand Down

0 comments on commit d92d848

Please sign in to comment.