diff --git a/CHANGELOG.md b/CHANGELOG.md index bb383a79..946b3545 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,7 @@ Any violations of this scheme are considered to be bugs. * [#516](https://github.com/hashie/hashie/issues/516): Fixed `NoMethodError` raised when including `Hashie::Extensions::Mash::SymbolizeKeys` and `Hashie::Extensions::SymbolizeKeys` in mashes/hashes with non string or symbol keys - [@carolineartz](https://github.com/carolineartz). * [#531](https://github.com/hashie/hashie/pull/531): Fixed [slice doesn't work using symbols](https://github.com/hashie/hashie/issues/529) using hash with `IndifferentAccess` extension - [@gnomex](https://github.com/gnomex). * [#533](https://github.com/hashie/hashie/pull/533): Fixed `NoMethodError: undefined method `to_json'` at `hashie/dash_spec` - [@gnomex](https://github.com/gnomex). +* [#535](https://github.com/hashie/hashie/pull/535): Restored the exporting of all properties as part of `Dash#to_h` and `Dash#to_hash` - [@michaelherold](https://github.com/michaelherold). * Your contribution here. ### Security diff --git a/lib/hashie/dash.rb b/lib/hashie/dash.rb index 460790b2..89a77a15 100644 --- a/lib/hashie/dash.rb +++ b/lib/hashie/dash.rb @@ -169,6 +169,13 @@ def replace(other_hash) self end + def to_h + defaults = ::Hash[self.class.properties.map { |prop| [prop, self.class.defaults[prop]] }] + + defaults.merge(self) + end + alias to_hash to_h + def update_attributes!(attributes) update_attributes(attributes) diff --git a/lib/hashie/extensions/dash/indifferent_access.rb b/lib/hashie/extensions/dash/indifferent_access.rb index 204cae6d..50d4f935 100644 --- a/lib/hashie/extensions/dash/indifferent_access.rb +++ b/lib/hashie/extensions/dash/indifferent_access.rb @@ -19,6 +19,15 @@ def self.requires_class_methods?(klass) end private_class_method :requires_class_methods? + def to_h + defaults = ::Hash[self.class.properties.map do |prop| + [Hashie::Extensions::IndifferentAccess.convert_key(prop), self.class.defaults[prop]] + end] + + defaults.merge(self) + end + alias to_hash to_h + module ClassMethods # Check to see if the specified property has already been # defined. diff --git a/spec/hashie/dash_spec.rb b/spec/hashie/dash_spec.rb index 387f0cb1..20ffb331 100644 --- a/spec/hashie/dash_spec.rb +++ b/spec/hashie/dash_spec.rb @@ -416,6 +416,7 @@ class KeepingMash < Hashie::Mash Class.new(Hashie::Dash) do property :a, required: -> { b.nil? }, message: 'is required if b is not set.' property :b, required: -> { a.nil? }, message: 'is required if a is not set.' + property :c, default: -> { 'c' } end end @@ -434,6 +435,40 @@ class KeepingMash < Hashie::Mash it 'raises an error when neither property is set' do expect { codependent.new(a: nil, b: nil) }.to raise_error(ArgumentError) end + + context 'exporting nil values' do + describe '#to_h' do + it 'does not prune nil values' do + expect(codependent.new(a: 'hi', b: nil).to_h).to eq(a: 'hi', b: nil, c: 'c') + expect(codependent.new(a: 'hi', b: nil, c: nil).to_hash).to eq(a: 'hi', b: nil, c: 'c') + expect(codependent.new(a: 'hi', b: nil).merge(c: nil).to_h).to eq(a: 'hi', b: nil, c: nil) + end + end + + describe '#to_hash' do + it 'does not prune nil values' do + expect(codependent.new(a: 'hi', b: nil).to_hash).to eq(a: 'hi', b: nil, c: 'c') + expect(codependent.new(a: 'hi', b: nil, c: nil).to_hash).to eq(a: 'hi', b: nil, c: 'c') + expect(codependent.new(a: 'hi', b: nil).merge(c: nil).to_hash).to eq(a: 'hi', b: nil, c: nil) + end + end + + describe '**' do + # Note: This test is an implementation detail of MRI and may not hold for + # other Ruby interpreters. But it's important to note in the test suite + # because it can be surprising for people unfamiliar with the semantics of + # double-splatting. + # + # For more information, see [this link][1]: + # + # [1]: https://github.com/hashie/hashie/issues/353#issuecomment-363294886 + it 'prunes nil values because they are not set in the dash' do + dash = codependent.new(a: 'hi', b: nil) + + expect(**dash).to eq(a: 'hi', c: 'c') + end + end + end end end end @@ -482,6 +517,43 @@ class KeepingMash < Hashie::Mash expect(@bottom.new).to have_key(:echo) expect(@bottom.new).to_not have_key('echo') end + + context 'exporting nil values' do + let(:test) do + Class.new(Hashie::Dash) do + property :foo + property :bar + end + end + + describe '#to_h' do + it 'does not prune nil values' do + expect(test.new(foo: 'hi', bar: nil).to_h).to eq(foo: 'hi', bar: nil) + end + end + + describe '#to_hash' do + it 'does not prune nil values' do + expect(test.new(foo: 'hi', bar: nil).to_hash).to eq(foo: 'hi', bar: nil) + end + end + + describe '**' do + # Note: This test is an implementation detail of MRI and may not hold for + # other Ruby interpreters. But it's important to note in the test suite + # because it can be surprising for people unfamiliar with the semantics of + # double-splatting. + # + # For more information, see [this link][1]: + # + # [1]: https://github.com/hashie/hashie/issues/353#issuecomment-363294886 + it 'prunes nil values because they are not set in the dash' do + dash = test.new(foo: 'hi', bar: nil) + + expect(**dash).to eq(foo: 'hi') + end + end + end end describe SubclassedTest do