From 25fe2f747ee06e563808e08493ec7a471cc82b26 Mon Sep 17 00:00:00 2001 From: Bobby McDonald Date: Tue, 14 Jan 2020 08:50:43 -0500 Subject: Fix except use in Mash#load (#508) --- .travis.yml | 1 + CHANGELOG.md | 2 + lib/hashie/extensions/deep_merge.rb | 2 + lib/hashie/mash.rb | 5 +- spec/hashie/dash_spec.rb | 4 +- spec/hashie/extensions/deep_find_spec.rb | 36 -- spec/hashie/extensions/deep_locate_spec.rb | 13 - .../indifferent_access_with_rails_hwia_spec.rb | 208 ------------ spec/hashie/mash_spec.rb | 26 +- spec/integration/active_support/Gemfile | 15 + .../integration/active_support/integration_spec.rb | 371 +++++++++++++++++++++ spec/spec_helper.rb | 3 - 12 files changed, 403 insertions(+), 283 deletions(-) create mode 100644 spec/integration/active_support/Gemfile create mode 100644 spec/integration/active_support/integration_spec.rb diff --git a/.travis.yml b/.travis.yml index 17f14c1..a78ca26 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,6 +28,7 @@ matrix: dist: bionic - rvm: rbx-3 dist: trusty + bundler_args: --retry 0 - rvm: jruby-9.0.5.0 dist: trusty - rvm: jruby-head diff --git a/CHANGELOG.md b/CHANGELOG.md index 665e6c4..2f5c487 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,8 @@ scheme are considered to be bugs. * [#467](https://github.com/intridea/hashie/pull/467): Fixed `DeepMerge#deep_merge` mutating nested values within the receiver - [@michaelherold](https://github.com/michaelherold). * [#505](https://github.com/hashie/hashie/pull/505): Ensure that `Hashie::Array`s are not deconverted within `Hashie::Mash`es to make `Mash#dig` work properly - [@michaelherold](https://github.com/michaelherold). * [#507](https://github.com/hashie/hashie/pull/507): Suppress `Psych.safe_load` arg warn when using Psych 3.1.0+ - [@koic](https://github.com/koic). +* [#508](https://github.com/hashie/hashie/pull/508): Fixed `Mash.load` no longer uses Rails-only `#except` - [@bobbymcwho](https://github.com/bobbymcwho). +* [#508](https://github.com/hashie/hashie/pull/508): Fixed `Hashie::Extensions::DeepMerge` `#deep_merge` not correctly dup'ing sub-hashes if active_support hash extensions were not present - [@bobbymcwho](https://github.com/bobbymcwho). * [#510](https://github.com/hashie/hashie/pull/510): Ensure that `Hashie::Mash#compact` is only defined on Ruby version >= 2.4.0 - [@bobbymcwho](https://github.com/bobbymcwho). * Your contribution here. diff --git a/lib/hashie/extensions/deep_merge.rb b/lib/hashie/extensions/deep_merge.rb index 1890e8f..24fa679 100644 --- a/lib/hashie/extensions/deep_merge.rb +++ b/lib/hashie/extensions/deep_merge.rb @@ -38,6 +38,8 @@ module Hashie hash[k] = if hash.key?(k) && hash[k].is_a?(::Hash) && v.is_a?(::Hash) _recursive_merge(hash[k], v, &block) + elsif v.is_a?(::Hash) + _recursive_merge({}, v, &block) elsif hash.key?(k) && block_given? yield(k, hash[k], v) else diff --git a/lib/hashie/mash.rb b/lib/hashie/mash.rb index 658aded..97f75d5 100644 --- a/lib/hashie/mash.rb +++ b/lib/hashie/mash.rb @@ -74,8 +74,9 @@ module Hashie return @_mashes[path] if @_mashes.key?(path) raise ArgumentError, "The following file doesn't exist: #{path}" unless File.file?(path) - parser = options.fetch(:parser) { Hashie::Extensions::Parsers::YamlErbParser } - @_mashes[path] = new(parser.perform(path, options.except(:parser))).freeze + options = options.dup + parser = options.delete(:parser) { Hashie::Extensions::Parsers::YamlErbParser } + @_mashes[path] = new(parser.perform(path, options)).freeze end def to_module(mash_method_name = :settings) diff --git a/spec/hashie/dash_spec.rb b/spec/hashie/dash_spec.rb index 5c49026..5f3bfe3 100644 --- a/spec/hashie/dash_spec.rb +++ b/spec/hashie/dash_spec.rb @@ -56,9 +56,9 @@ class DeferredWithSelfTest < Hashie::Dash end describe DashTestDefaultProc do - it 'as_json behaves correctly with default proc' do + it 'to_json behaves correctly with default proc' do object = described_class.new - expect(object.as_json).to be == { 'fields' => [] } + expect(object.to_json).to be == '{"fields":[]}' end end diff --git a/spec/hashie/extensions/deep_find_spec.rb b/spec/hashie/extensions/deep_find_spec.rb index cd13d7f..fddb9d1 100644 --- a/spec/hashie/extensions/deep_find_spec.rb +++ b/spec/hashie/extensions/deep_find_spec.rb @@ -1,5 +1,4 @@ require 'spec_helper' -require 'active_support/core_ext/hash/indifferent_access' describe Hashie::Extensions::DeepFind do subject { Class.new(Hash) { include Hashie::Extensions::DeepFind } } @@ -71,41 +70,6 @@ describe Hashie::Extensions::DeepFind do end end - context 'on an ActiveSupport::HashWithIndifferentAccess' do - subject(:instance) { hash.with_indifferent_access.extend(Hashie::Extensions::DeepFind) } - - describe '#deep_find' do - it 'indifferently detects a value from a nested hash' do - expect(instance.deep_find(:address)).to eq('123 Library St.') - expect(instance.deep_find('address')).to eq('123 Library St.') - end - - it 'indifferently detects a value from a nested array' do - expect(instance.deep_find(:title)).to eq('Call of the Wild') - expect(instance.deep_find('title')).to eq('Call of the Wild') - end - - it 'indifferently returns nil if it does not find a match' do - expect(instance.deep_find(:wahoo)).to be_nil - expect(instance.deep_find('wahoo')).to be_nil - end - end - - describe '#deep_find_all' do - it 'indifferently detects all values from a nested hash' do - expect(instance.deep_find_all(:title)) - .to eq(['Call of the Wild', 'Moby Dick', 'Main Library']) - expect(instance.deep_find_all('title')) - .to eq(['Call of the Wild', 'Moby Dick', 'Main Library']) - end - - it 'indifferently returns nil if it does not find any matches' do - expect(instance.deep_find_all(:wahoo)).to be_nil - expect(instance.deep_find_all('wahoo')).to be_nil - end - end - end - context 'on a Hash including Hashie::Extensions::IndifferentAccess' do let(:klass) { Class.new(Hash) { include Hashie::Extensions::IndifferentAccess } } subject(:instance) { klass[hash.dup].extend(Hashie::Extensions::DeepFind) } diff --git a/spec/hashie/extensions/deep_locate_spec.rb b/spec/hashie/extensions/deep_locate_spec.rb index 6c2fcf0..e104e76 100644 --- a/spec/hashie/extensions/deep_locate_spec.rb +++ b/spec/hashie/extensions/deep_locate_spec.rb @@ -1,5 +1,4 @@ require 'spec_helper' -require 'active_support/core_ext/hash/indifferent_access' describe Hashie::Extensions::DeepLocate do let(:hash) do @@ -123,16 +122,4 @@ describe Hashie::Extensions::DeepLocate do expect(instance.deep_locate(:bool)).to eq([hash[:query]]) end end - - context 'on an ActiveSupport::HashWithIndifferentAccess' do - let(:instance) { hash.dup.with_indifferent_access } - - it 'can locate symbolic keys' do - expect(described_class.deep_locate(:lsr10, instance)).to eq ['lsr10' => { 'gte' => 2014 }] - end - - it 'can locate string keys' do - expect(described_class.deep_locate('lsr10', instance)).to eq ['lsr10' => { 'gte' => 2014 }] - end - end end diff --git a/spec/hashie/extensions/indifferent_access_with_rails_hwia_spec.rb b/spec/hashie/extensions/indifferent_access_with_rails_hwia_spec.rb index c53c531..e69de29 100644 --- a/spec/hashie/extensions/indifferent_access_with_rails_hwia_spec.rb +++ b/spec/hashie/extensions/indifferent_access_with_rails_hwia_spec.rb @@ -1,208 +0,0 @@ -# This set of tests verifies that Hashie::Extensions::IndifferentAccess works with -# ActiveSupport HashWithIndifferentAccess hashes. See #164 and #166 for details. - -require 'active_support/hash_with_indifferent_access' -require 'active_support/core_ext/hash' -require 'spec_helper' - -describe Hashie::Extensions::IndifferentAccess do - class IndifferentHashWithMergeInitializer < Hash - include Hashie::Extensions::MergeInitializer - include Hashie::Extensions::IndifferentAccess - - class << self - alias build new - end - end - - class IndifferentHashWithArrayInitializer < Hash - include Hashie::Extensions::IndifferentAccess - - class << self - alias build [] - end - end - - class IndifferentHashWithTryConvertInitializer < Hash - include Hashie::Extensions::IndifferentAccess - - class << self - alias build try_convert - end - end - - class CoercableHash < Hash - include Hashie::Extensions::Coercion - include Hashie::Extensions::MergeInitializer - end - - class MashWithIndifferentAccess < Hashie::Mash - include Hashie::Extensions::IndifferentAccess - end - - shared_examples_for 'hash with indifferent access' do - it 'is able to access via string or symbol' do - indifferent_hash = ActiveSupport::HashWithIndifferentAccess.new(abc: 123) - h = subject.build(indifferent_hash) - expect(h[:abc]).to eq 123 - expect(h['abc']).to eq 123 - end - - describe '#values_at' do - it 'indifferently finds values' do - indifferent_hash = ActiveSupport::HashWithIndifferentAccess.new( - :foo => 'bar', 'baz' => 'qux' - ) - h = subject.build(indifferent_hash) - expect(h.values_at('foo', :baz)).to eq %w[bar qux] - end - end - - describe '#fetch' do - it 'works like normal fetch, but indifferent' do - indifferent_hash = ActiveSupport::HashWithIndifferentAccess.new(foo: 'bar') - h = subject.build(indifferent_hash) - expect(h.fetch(:foo)).to eq h.fetch('foo') - expect(h.fetch(:foo)).to eq 'bar' - end - end - - describe '#delete' do - it 'deletes indifferently' do - indifferent_hash = ActiveSupport::HashWithIndifferentAccess.new( - :foo => 'bar', - 'baz' => 'qux' - ) - h = subject.build(indifferent_hash) - h.delete('foo') - h.delete(:baz) - expect(h).to be_empty - end - end - - describe '#key?' do - let(:h) do - indifferent_hash = ActiveSupport::HashWithIndifferentAccess.new(foo: 'bar') - subject.build(indifferent_hash) - end - - it 'finds it indifferently' do - expect(h).to be_key(:foo) - expect(h).to be_key('foo') - end - - %w[include? member? has_key?].each do |key_alias| - it "is aliased as #{key_alias}" do - expect(h.send(key_alias.to_sym, :foo)).to be(true) - expect(h.send(key_alias.to_sym, 'foo')).to be(true) - end - end - end - - describe '#update' do - let(:h) do - indifferent_hash = ActiveSupport::HashWithIndifferentAccess.new(foo: 'bar') - subject.build(indifferent_hash) - end - - it 'allows keys to be indifferent still' do - h.update(baz: 'qux') - expect(h['foo']).to eq 'bar' - expect(h['baz']).to eq 'qux' - end - - it 'recursively injects indifference into sub-hashes' do - h.update(baz: { qux: 'abc' }) - expect(h['baz']['qux']).to eq 'abc' - end - - it 'does not change the ancestors of the injected object class' do - h.update(baz: { qux: 'abc' }) - expect({}).not_to be_respond_to(:indifferent_access?) - end - end - - describe '#replace' do - let(:h) do - indifferent_hash = ActiveSupport::HashWithIndifferentAccess.new(foo: 'bar') - subject.build(indifferent_hash).replace(bar: 'baz', hi: 'bye') - end - - it 'returns self' do - expect(h).to be_a(subject) - end - - it 'removes old keys' do - [:foo, 'foo'].each do |k| - expect(h[k]).to be_nil - expect(h.key?(k)).to be_falsy - end - end - - it 'creates new keys with indifferent access' do - [:bar, 'bar', :hi, 'hi'].each { |k| expect(h.key?(k)).to be_truthy } - expect(h[:bar]).to eq 'baz' - expect(h['bar']).to eq 'baz' - expect(h[:hi]).to eq 'bye' - expect(h['hi']).to eq 'bye' - end - end - - describe '#try_convert' do - describe 'with conversion' do - let(:h) do - indifferent_hash = ActiveSupport::HashWithIndifferentAccess.new(foo: 'bar') - subject.try_convert(indifferent_hash) - end - - it 'is a subject' do - expect(h).to be_a(subject) - end - end - - describe 'without conversion' do - let(:h) { subject.try_convert('{ :foo => bar }') } - - it 'is nil' do - expect(h).to be_nil - end - end - end - end - - describe 'with merge initializer' do - subject { IndifferentHashWithMergeInitializer } - it_should_behave_like 'hash with indifferent access' - end - - describe 'with array initializer' do - subject { IndifferentHashWithArrayInitializer } - it_should_behave_like 'hash with indifferent access' - end - - describe 'with try convert initializer' do - subject { IndifferentHashWithTryConvertInitializer } - it_should_behave_like 'hash with indifferent access' - end - - describe 'with coercion' do - subject { CoercableHash } - - let(:instance) { subject.new } - - it 'supports coercion for ActiveSupport::HashWithIndifferentAccess' do - subject.coerce_key :foo, ActiveSupport::HashWithIndifferentAccess.new(Coercable => Coercable) - instance[:foo] = { 'bar_key' => 'bar_value', 'bar2_key' => 'bar2_value' } - expect(instance[:foo].keys).to all(be_coerced) - expect(instance[:foo].values).to all(be_coerced) - expect(instance[:foo]).to be_a(ActiveSupport::HashWithIndifferentAccess) - end - end - - describe 'Mash with indifferent access' do - it 'is able to be created for a deep nested HashWithIndifferentAccess' do - indifferent_hash = ActiveSupport::HashWithIndifferentAccess.new(abc: { def: 123 }) - MashWithIndifferentAccess.new(indifferent_hash) - end - end -end diff --git a/spec/hashie/mash_spec.rb b/spec/hashie/mash_spec.rb index 603adc0..08e6f09 100644 --- a/spec/hashie/mash_spec.rb +++ b/spec/hashie/mash_spec.rb @@ -147,7 +147,7 @@ describe Hashie::Mash do mash[:test_key] = 'Test value' expect { mash[:test_key] = 'A new value' }.not_to raise_error - expect(logger_output).to be_blank + expect(logger_output).to be_empty end it 'does not write to the logger when warnings are disabled' do @@ -156,7 +156,7 @@ describe Hashie::Mash do end mash_class.new('trust' => { 'two' => 2 }) - expect(logger_output).to be_blank + expect(logger_output).to be_empty end it 'cannot disable logging on the base Mash' do @@ -173,7 +173,7 @@ describe Hashie::Mash do grandchild_class.new('trust' => { 'two' => 2 }) - expect(logger_output).to be_blank + expect(logger_output).to be_empty end it 'writes to logger when a key is overridden that is not ignored' do @@ -182,7 +182,7 @@ describe Hashie::Mash do end mash_class.new('address' => { 'zip' => '90210' }) - expect(logger_output).not_to be_blank + expect(logger_output).not_to be_empty end it 'does not write to logger when a key is overridden that is ignored' do @@ -191,7 +191,7 @@ describe Hashie::Mash do end mash_class.new('address' => { 'zip' => '90210' }) - expect(logger_output).to be_blank + expect(logger_output).to be_empty end it 'carries over the ignored warnings list for warnings on grandchild classes' do @@ -203,7 +203,7 @@ describe Hashie::Mash do grandchild_class.new('address' => { 'zip' => '90210' }, 'merge' => true) expect(grandchild_class.disabled_warnings).to eq(%i[zip merge]) - expect(logger_output).to be_blank + expect(logger_output).to be_empty end context 'multiple disable_warnings calls' do @@ -229,7 +229,7 @@ describe Hashie::Mash do child_class.new('address' => { 'zip' => '90210' }, 'merge' => true, 'cycle' => 'bi') expect(child_class.disabled_warnings).to eq([]) - expect(logger_output).to be_blank + expect(logger_output).to be_empty end end @@ -848,18 +848,6 @@ describe Hashie::Mash do end end - describe '#extractable_options?' do - require 'active_support' - - subject { described_class.new(name: 'foo') } - let(:args) { [101, 'bar', subject] } - - it 'can be extracted from an array' do - expect(args.extract_options!).to eq subject - expect(args).to eq [101, 'bar'] - end - end - describe '#reverse_merge' do subject { described_class.new(a: 1, b: 2) } diff --git a/spec/integration/active_support/Gemfile b/spec/integration/active_support/Gemfile new file mode 100644 index 0000000..eee6625 --- /dev/null +++ b/spec/integration/active_support/Gemfile @@ -0,0 +1,15 @@ +source 'http://rubygems.org' + +gem 'hashie', path: '../../..' +require File.expand_path('../../../../lib/hashie/extensions/ruby_version', __FILE__) + +# rubocop:disable Bundler/DuplicatedGem +if Hashie::Extensions::RubyVersion.new(RUBY_VERSION) >= Hashie::Extensions::RubyVersion.new('2.4.0') + gem 'activesupport', '~> 5.x', require: false +else + gem 'activesupport', '~> 4.x', require: false +end +# rubocop:enable Bundler/DuplicatedGem + +gem 'rake' +gem 'rspec', '~> 3.5.0' diff --git a/spec/integration/active_support/integration_spec.rb b/spec/integration/active_support/integration_spec.rb new file mode 100644 index 0000000..e0503c8 --- /dev/null +++ b/spec/integration/active_support/integration_spec.rb @@ -0,0 +1,371 @@ +require 'active_support' +require 'active_support/core_ext' +require 'active_support/core_ext/hash/indifferent_access' +require 'active_support/core_ext/hash' +require 'hashie' + +RSpec.configure do |config| + config.expect_with :rspec do |expect| + expect.syntax = :expect + end +end + +RSpec.describe Hashie::Mash do + describe '#extractable_options?' do + subject { Hashie::Mash.new(name: 'foo') } + let(:args) { [101, 'bar', subject] } + + it 'can be extracted from an array' do + expect(args.extract_options!).to eq subject + expect(args).to eq [101, 'bar'] + end + end +end + +RSpec.describe Hashie::Extensions::DeepFind do + let(:hash) do + { + library: { + books: [ + { title: 'Call of the Wild' }, + { title: 'Moby Dick' } + ], + shelves: nil, + location: { + address: '123 Library St.', + title: 'Main Library' + } + } + } + end + + subject(:instance) { hash.with_indifferent_access.extend(Hashie::Extensions::DeepFind) } + + describe '#deep_find' do + it 'indifferently detects a value from a nested hash' do + expect(instance.deep_find(:address)).to eq('123 Library St.') + expect(instance.deep_find('address')).to eq('123 Library St.') + end + + it 'indifferently detects a value from a nested array' do + expect(instance.deep_find(:title)).to eq('Call of the Wild') + expect(instance.deep_find('title')).to eq('Call of the Wild') + end + + it 'indifferently returns nil if it does not find a match' do + expect(instance.deep_find(:wahoo)).to be_nil + expect(instance.deep_find('wahoo')).to be_nil + end + end + + describe '#deep_find_all' do + it 'indifferently detects all values from a nested hash' do + expect(instance.deep_find_all(:title)) + .to eq(['Call of the Wild', 'Moby Dick', 'Main Library']) + expect(instance.deep_find_all('title')) + .to eq(['Call of the Wild', 'Moby Dick', 'Main Library']) + end + + it 'indifferently returns nil if it does not find any matches' do + expect(instance.deep_find_all(:wahoo)).to be_nil + expect(instance.deep_find_all('wahoo')).to be_nil + end + end +end + +RSpec.describe Hashie::Extensions::DeepLocate do + let(:hash) do + { + from: 0, + size: 25, + query: { + bool: { + must: [ + { + query_string: { + query: 'foobar', + default_operator: 'AND', + fields: [ + 'title^2', + '_all' + ] + } + }, + { + match: { + field_1: 'value_1' + } + }, + { + range: { + lsr09: { + gte: 2014 + } + } + } + ], + should: [ + { + match: { + field_2: 'value_2' + } + } + ], + must_not: [ + { + range: { + lsr10: { + gte: 2014 + } + } + } + ] + } + } + } + end + + describe '#deep_locate' do + subject(:instance) { hash.with_indifferent_access.extend(described_class) } + + it 'can locate symbolic keys' do + expect(described_class.deep_locate(:lsr10, instance)).to eq ['lsr10' => { 'gte' => 2014 }] + end + + it 'can locate string keys' do + expect(described_class.deep_locate('lsr10', instance)).to eq ['lsr10' => { 'gte' => 2014 }] + end + end +end + +RSpec.describe Hashie::Extensions::IndifferentAccess do + class Initializable + attr_reader :coerced, :value + + def initialize(obj, coerced = nil) + @coerced = coerced + @value = obj.class.to_s + end + + def coerced? + !@coerced.nil? + end + end + + class Coercable < Initializable + def self.coerce(obj) + new(obj, true) + end + end + + class IndifferentHashWithMergeInitializer < Hash + include Hashie::Extensions::MergeInitializer + include Hashie::Extensions::IndifferentAccess + + class << self + alias build new + end + end + + class IndifferentHashWithArrayInitializer < Hash + include Hashie::Extensions::IndifferentAccess + + class << self + alias build [] + end + end + + class IndifferentHashWithTryConvertInitializer < Hash + include Hashie::Extensions::IndifferentAccess + + class << self + alias build try_convert + end + end + + class CoercableHash < Hash + include Hashie::Extensions::Coercion + include Hashie::Extensions::MergeInitializer + end + + class MashWithIndifferentAccess < Hashie::Mash + include Hashie::Extensions::IndifferentAccess + end + + shared_examples_for 'hash with indifferent access' do + it 'is able to access via string or symbol' do + indifferent_hash = ActiveSupport::HashWithIndifferentAccess.new(abc: 123) + h = subject.build(indifferent_hash) + expect(h[:abc]).to eq 123 + expect(h['abc']).to eq 123 + end + + describe '#values_at' do + it 'indifferently finds values' do + indifferent_hash = ActiveSupport::HashWithIndifferentAccess.new( + :foo => 'bar', 'baz' => 'qux' + ) + h = subject.build(indifferent_hash) + expect(h.values_at('foo', :baz)).to eq %w[bar qux] + end + end + + describe '#fetch' do + it 'works like normal fetch, but indifferent' do + indifferent_hash = ActiveSupport::HashWithIndifferentAccess.new(foo: 'bar') + h = subject.build(indifferent_hash) + expect(h.fetch(:foo)).to eq h.fetch('foo') + expect(h.fetch(:foo)).to eq 'bar' + end + end + + describe '#delete' do + it 'deletes indifferently' do + indifferent_hash = ActiveSupport::HashWithIndifferentAccess.new( + :foo => 'bar', + 'baz' => 'qux' + ) + h = subject.build(indifferent_hash) + h.delete('foo') + h.delete(:baz) + expect(h).to be_empty + end + end + + describe '#key?' do + let(:h) do + indifferent_hash = ActiveSupport::HashWithIndifferentAccess.new(foo: 'bar') + subject.build(indifferent_hash) + end + + it 'finds it indifferently' do + expect(h).to be_key(:foo) + expect(h).to be_key('foo') + end + + %w[include? member? has_key?].each do |key_alias| + it "is aliased as #{key_alias}" do + expect(h.send(key_alias.to_sym, :foo)).to be(true) + expect(h.send(key_alias.to_sym, 'foo')).to be(true) + end + end + end + + describe '#update' do + let(:h) do + indifferent_hash = ActiveSupport::HashWithIndifferentAccess.new(foo: 'bar') + subject.build(indifferent_hash) + end + + it 'allows keys to be indifferent still' do + h.update(baz: 'qux') + expect(h['foo']).to eq 'bar' + expect(h['baz']).to eq 'qux' + end + + it 'recursively injects indifference into sub-hashes' do + h.update(baz: { qux: 'abc' }) + expect(h['baz']['qux']).to eq 'abc' + end + + it 'does not change the ancestors of the injected object class' do + h.update(baz: { qux: 'abc' }) + expect({}).not_to be_respond_to(:indifferent_access?) + end + end + + describe '#replace' do + let(:h) do + indifferent_hash = ActiveSupport::HashWithIndifferentAccess.new(foo: 'bar') + subject.build(indifferent_hash).replace(bar: 'baz', hi: 'bye') + end + + it 'returns self' do + expect(h).to be_a(subject) + end + + it 'removes old keys' do + [:foo, 'foo'].each do |k| + expect(h[k]).to be_nil + expect(h.key?(k)).to be_falsy + end + end + + it 'creates new keys with indifferent access' do + [:bar, 'bar', :hi, 'hi'].each { |k| expect(h.key?(k)).to be_truthy } + expect(h[:bar]).to eq 'baz' + expect(h['bar']).to eq 'baz' + expect(h[:hi]).to eq 'bye' + expect(h['hi']).to eq 'bye' + end + end + + describe '#try_convert' do + describe 'with conversion' do + let(:h) do + indifferent_hash = ActiveSupport::HashWithIndifferentAccess.new(foo: 'bar') + subject.try_convert(indifferent_hash) + end + + it 'is a subject' do + expect(h).to be_a(subject) + end + end + + describe 'without conversion' do + let(:h) { subject.try_convert('{ :foo => bar }') } + + it 'is nil' do + expect(h).to be_nil + end + end + end + end + + describe 'with merge initializer' do + subject { IndifferentHashWithMergeInitializer } + it_should_behave_like 'hash with indifferent access' + end + + describe 'with array initializer' do + subject { IndifferentHashWithArrayInitializer } + it_should_behave_like 'hash with indifferent access' + end + + describe 'with try convert initializer' do + subject { IndifferentHashWithTryConvertInitializer } + it_should_behave_like 'hash with indifferent access' + end + + describe 'with coercion' do + subject { CoercableHash } + + let(:instance) { subject.new } + + it 'supports coercion for ActiveSupport::HashWithIndifferentAccess' do + subject.coerce_key :foo, ActiveSupport::HashWithIndifferentAccess.new(Coercable => Coercable) + instance[:foo] = { 'bar_key' => 'bar_value', 'bar2_key' => 'bar2_value' } + expect(instance[:foo].keys).to all(be_coerced) + expect(instance[:foo].values).to all(be_coerced) + expect(instance[:foo]).to be_a(ActiveSupport::HashWithIndifferentAccess) + end + end + + describe 'Mash with indifferent access' do + it 'is able to be created for a deep nested HashWithIndifferentAccess' do + indifferent_hash = ActiveSupport::HashWithIndifferentAccess.new(abc: { def: 123 }) + MashWithIndifferentAccess.new(indifferent_hash) + end + end + + class DashTestDefaultProc < Hashie::Dash + property :fields, default: -> { [] } + end + + describe DashTestDefaultProc do + it 'as_json behaves correctly with default proc' do + object = described_class.new + expect(object.as_json).to be == { 'fields' => [] } + end + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index b061f22..dc31d61 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -11,9 +11,6 @@ require 'rspec/pending_for' require './spec/support/ruby_version_check' require './spec/support/logger' -require 'active_support' -require 'active_support/core_ext' - RSpec.configure do |config| config.extend RubyVersionCheck config.expect_with :rspec do |expect| -- cgit v1.2.1