Skip to content

Instantly share code, notes, and snippets.

@DonSchado
Last active October 15, 2019 10:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DonSchado/171b1e758bd6c649e36c5948cebb21df to your computer and use it in GitHub Desktop.
Save DonSchado/171b1e758bd6c649e36c5948cebb21df to your computer and use it in GitHub Desktop.
Railslove Ruby programming exercise A4
# Railslove Ruby programming exercise A4
#
# To run the following exercise you need to have rspec installed.
# Then inspect the failing specs by running `rspec translations.rb`
#
# This excercise is special, because it's the first one where you're allowed to require active_support. ;-)
#
# (!) The task is to navigate and write into a nested hash via a path represented as `.` separated keys.
#
# (?) Maybe start with the underling algorithm to expand a collection to a "directed graph"
# and then implement the rest of the `#set` method to make the tests pass.
#
# Refactor until you're happy with your solution, by asking the follwing questions:
# * Is the code understandable/maintainable?
# * Do I really need all these if/else/elsif statements?
#
require 'active_support'
class TranslationsHash
attr_reader :translations
def initialize(translations = {})
@translations = translations
end
def set(path, value)
# TODO: this should call somehow the private method
end
private
def expand_to_directed_hash(collection)
# your code goes here
end
end
# # don't touch me
require 'rspec'
RSpec.describe 'TranslationsHash' do
let(:data) do
{ foo: { bar: 'value' } }
end
subject(:translations) { TranslationsHash.new(data) }
describe '#expand_to_directed_hash' do
let(:expansion) { subject.method(:expand_to_directed_hash) }
it { expect(expansion.call([:a, 'v'])).to eq({ a: 'v' }) }
it { expect(expansion.call([:a, :b, 'v'])).to eq({ a: { b: 'v' } }) }
it { expect(expansion.call([:a, :b, :c, 'v'])).to eq({ a: { b: { c: 'v' } } }) }
it { expect(expansion.call([:a, :b, :c, :d, 'v'])).to eq({ a: { b: { c: { d: 'v' } } } }) }
it { expect(expansion.call([:a, :b, :c, :d, { e: 'f' }])).to eq({ a: { b: { c: { d: { e: 'f' } } } } }) }
end
describe '#set' do
it 'overwrites values when last in the chain' do
expect(subject.set('foo', nil)).to match({ foo: nil })
expect(subject.set('foo', 'bar')).to match({ foo: 'bar' })
expect(subject.set('foo', [])).to match({ foo: [] })
end
it 'does not merge empty hash (due to #deep_merge, if required use #merge for this case)' do
expect(subject.set('foo', {})).to match(data)
end
it 'navigates dots to deep merge values' do
expect(subject.set('foo.baz', 'yay')).to match({ foo: { bar: 'value' , baz: 'yay' } })
expect(subject.set('foo.baz.we.need.to.go', 'deeper')).
to match(hash_including({ foo: { bar: 'value', baz: { we: { need: { to: { go: 'deeper' } } } } } }))
end
context 'nested value merge' do
let(:data) do
{ foo: { bar: { countries: { fr: 'FR' } } } }
end
it 'deep merges current data via key or value' do
expect(subject.set('foo.bar', { countries: { de: 'DE' } })).
to match({ foo: { bar: { countries: { fr: 'FR', de: 'DE' } } } } )
expect(subject.set('foo', { bar: { countries: { de: 'DE' } } })).
to match({ foo: { bar: { countries: { fr: 'FR', de: 'DE' } } } } )
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment