Skip to content

Instantly share code, notes, and snippets.

@dogweather
Last active February 18, 2020 11:40
Show Gist options
  • Save dogweather/819ccdb41c9db0514c163cfdb1c528e2 to your computer and use it in GitHub Desktop.
Save dogweather/819ccdb41c9db0514c163cfdb1c528e2 to your computer and use it in GitHub Desktop.
DigBang: Safely unsafe hash traversal
# `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
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