Last active
February 18, 2020 11:40
-
-
Save dogweather/819ccdb41c9db0514c163cfdb1c528e2 to your computer and use it in GitHub Desktop.
DigBang: Safely unsafe hash traversal
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# `Hash#dig!` | |
# | |
# Like Ruby 2.3's `Hash#dig`, but raises an exception instead of returning `nil` | |
# when a key isn't found. | |
# | |
# Ruby 2.3 introduces the new Hash#dig method for safe extraction of | |
# a nested value. See http://ruby-doc.org/core-2.3.0/Hash.html#method-i-dig. | |
# It is the equivalent of a safely repeated Hash#[]. | |
# | |
# `#dig!`, on the other hand, is the equivalent of a repeated `Hash#fetch`. It's | |
# 'safely unsafe', raising the appropriate `KeyError` anywhere down the line, or | |
# returning the value if it exists. | |
# | |
# @example | |
# places = { countries: { canada: true } } | |
# places.dig :countries, :canada # => true | |
# places.dig! :countries, :canada # => true | |
# places.dig :countries, :canada, :ontario # => nil | |
# places.dig! :countries, :canada, :ontario # => KeyError: Key not found: :ontario | |
# | |
class Hash | |
def dig!(*keys) | |
keys.reduce(self) { |a, e| a.fetch(e) } | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'spec_helper' | |
require 'ext/dig_bang' | |
DOG = { | |
name: 'Phoebe', | |
age: 7, | |
vaccinations: { | |
'2011-07-20' => :all | |
} | |
}.freeze | |
describe Hash do | |
describe '#dig!' do | |
it 'returns an existing key/value' do | |
expect( DOG.dig!(:name) ).to eq 'Phoebe' | |
end | |
it 'returns an existing key/value from a list' do | |
expect( DOG.dig!(:vaccinations, '2011-07-20') ).to eq :all | |
end | |
it 'raises a KeyError if a key is not found' do | |
expect { DOG.dig! :weight }.to raise_error(KeyError, /weight/) | |
end | |
it 'raises a KeyError if a sub-key is not found' do | |
expect { | |
DOG.dig! :vaccinations, '2012-01-01' | |
}.to raise_error(KeyError, /2012-01-01/) | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment