summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorMichael Herold <github@michaeljherold.com>2017-02-22 19:37:07 -0600
committerGitHub <noreply@github.com>2017-02-22 19:37:07 -0600
commitc071e4f9fdcd41b078e6be405f9cf54480b76c8e (patch)
treefe18b8cb2dadf6818dd2b4bc31ffaf33de55d627 /spec
parentb36de9402e80140248c74ea2ce08f7db94375c66 (diff)
downloadhashie-c071e4f9fdcd41b078e6be405f9cf54480b76c8e.tar.gz
Add an extension to maintain original Mash keys (#326)
One of the behaviors of Mash that we see regularly surprise users is that Mash stringifies any keys passed into it. This leads to unexpected lack of synergy between Mash and its cousins (particularly Dash), since the property DSLs do not handle indifferent key access. This extension ensures that the original keys are kept inside the Mash's data structure, at the expense of more costly logic for fetching information indifferently. I have included a benchmark that compares the two. The benchmark shows that when you are passing string keys into a Mash, using this extension will actually be _faster_ than the default implementation, but that the reverse is true when passing symbol keys. In #296, I tried to do this universally for all Mashes, which slowed down the fetching behavior for Mash significantly. I like this attempt much better because it allows users to opt into the new behavior if they want it, while still keeping the default implementation as-is. Fixes #196 by giving the option of keeping the original structure of the Mash when using it with Dash. Fixes #246 by giving the option of opting into keeping the original keys. Closes #296 by giving a more flexible path forward that doesn't change the semantics of the main Mash class.
Diffstat (limited to 'spec')
-rw-r--r--spec/hashie/dash_spec.rb26
-rw-r--r--spec/hashie/extensions/mash/keep_original_keys_spec.rb46
2 files changed, 72 insertions, 0 deletions
diff --git a/spec/hashie/dash_spec.rb b/spec/hashie/dash_spec.rb
index c6e6753..87e5bc3 100644
--- a/spec/hashie/dash_spec.rb
+++ b/spec/hashie/dash_spec.rb
@@ -192,6 +192,32 @@ describe DashTest do
end
end
+ context 'converting from a Mash' do
+ class ConvertingFromMash < Hashie::Dash
+ property :property, required: true
+ end
+
+ context 'without keeping the original keys' do
+ let(:mash) { Hashie::Mash.new(property: 'test') }
+
+ it 'does not pick up the property from the stringified key' do
+ expect { ConvertingFromMash.new(mash) }.to raise_error(NoMethodError)
+ end
+ end
+
+ context 'when keeping the original keys' do
+ class KeepingMash < Hashie::Mash
+ include Hashie::Extensions::Mash::KeepOriginalKeys
+ end
+
+ let(:mash) { KeepingMash.new(property: 'test') }
+
+ it 'picks up the property from the original key' do
+ expect { ConvertingFromMash.new(mash) }.not_to raise_error
+ end
+ end
+ end
+
describe '#new' do
it 'fails with non-existent properties' do
expect { described_class.new(bork: '') }.to raise_error(*no_property_error('bork'))
diff --git a/spec/hashie/extensions/mash/keep_original_keys_spec.rb b/spec/hashie/extensions/mash/keep_original_keys_spec.rb
new file mode 100644
index 0000000..6e3aa06
--- /dev/null
+++ b/spec/hashie/extensions/mash/keep_original_keys_spec.rb
@@ -0,0 +1,46 @@
+require 'spec_helper'
+
+RSpec.describe Hashie::Extensions::Mash::KeepOriginalKeys do
+ let(:keeping_mash) do
+ Class.new(Hashie::Mash) do
+ include Hashie::Extensions::Mash::KeepOriginalKeys
+ end
+ end
+
+ it 'keeps the keys in the resulting hash identical to the original' do
+ original = { :a => 'apple', 'b' => 'bottle' }
+ mash = keeping_mash.new(original)
+
+ expect(mash.to_hash).to eq(original)
+ end
+
+ it 'indifferently responds to keys' do
+ original = { :a => 'apple', 'b' => 'bottle' }
+ mash = keeping_mash.new(original)
+
+ expect(mash['a']).to eq(mash[:a])
+ expect(mash['b']).to eq(mash[:b])
+ end
+
+ it 'responds to all method accessors like a Mash' do
+ original = { :a => 'apple', 'b' => 'bottle' }
+ mash = keeping_mash.new(original)
+
+ expect(mash.a).to eq('apple')
+ expect(mash.a?).to eq(true)
+ expect(mash.b).to eq('bottle')
+ expect(mash.b?).to eq(true)
+ expect(mash.underbang_).to be_a(keeping_mash)
+ expect(mash.bang!).to be_a(keeping_mash)
+ expect(mash.predicate?).to eq(false)
+ end
+
+ it 'keeps the keys that are directly passed without converting them' do
+ original = { :a => 'apple', 'b' => 'bottle' }
+ mash = keeping_mash.new(original)
+
+ mash[:c] = 'cat'
+ mash['d'] = 'dog'
+ expect(mash.to_hash).to eq(:a => 'apple', 'b' => 'bottle', :c => 'cat', 'd' => 'dog')
+ end
+end