hashie 3.4.3 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +516 -129
  3. data/CONTRIBUTING.md +24 -7
  4. data/LICENSE +1 -1
  5. data/README.md +408 -50
  6. data/Rakefile +18 -1
  7. data/UPGRADING.md +157 -7
  8. data/hashie.gemspec +14 -8
  9. data/lib/hashie/array.rb +21 -0
  10. data/lib/hashie/clash.rb +24 -12
  11. data/lib/hashie/dash.rb +56 -31
  12. data/lib/hashie/extensions/active_support/core_ext/hash.rb +14 -0
  13. data/lib/hashie/extensions/array/pretty_inspect.rb +19 -0
  14. data/lib/hashie/extensions/coercion.rb +30 -17
  15. data/lib/hashie/extensions/dash/indifferent_access.rb +30 -1
  16. data/lib/hashie/extensions/dash/predefined_values.rb +88 -0
  17. data/lib/hashie/extensions/dash/property_translation.rb +59 -28
  18. data/lib/hashie/extensions/deep_fetch.rb +5 -3
  19. data/lib/hashie/extensions/deep_find.rb +14 -5
  20. data/lib/hashie/extensions/deep_locate.rb +40 -21
  21. data/lib/hashie/extensions/deep_merge.rb +26 -10
  22. data/lib/hashie/extensions/ignore_undeclared.rb +6 -4
  23. data/lib/hashie/extensions/indifferent_access.rb +49 -8
  24. data/lib/hashie/extensions/key_conflict_warning.rb +55 -0
  25. data/lib/hashie/extensions/mash/define_accessors.rb +90 -0
  26. data/lib/hashie/extensions/mash/keep_original_keys.rb +53 -0
  27. data/lib/hashie/extensions/mash/permissive_respond_to.rb +61 -0
  28. data/lib/hashie/extensions/mash/safe_assignment.rb +3 -1
  29. data/lib/hashie/extensions/mash/symbolize_keys.rb +38 -0
  30. data/lib/hashie/extensions/method_access.rb +77 -19
  31. data/lib/hashie/extensions/parsers/yaml_erb_parser.rb +29 -5
  32. data/lib/hashie/extensions/ruby_version.rb +60 -0
  33. data/lib/hashie/extensions/ruby_version_check.rb +21 -0
  34. data/lib/hashie/extensions/strict_key_access.rb +16 -13
  35. data/lib/hashie/extensions/stringify_keys.rb +1 -1
  36. data/lib/hashie/extensions/symbolize_keys.rb +13 -2
  37. data/lib/hashie/hash.rb +18 -11
  38. data/lib/hashie/logger.rb +18 -0
  39. data/lib/hashie/mash.rb +177 -43
  40. data/lib/hashie/railtie.rb +21 -0
  41. data/lib/hashie/rash.rb +7 -7
  42. data/lib/hashie/utils.rb +44 -0
  43. data/lib/hashie/version.rb +1 -1
  44. data/lib/hashie.rb +33 -17
  45. metadata +28 -95
  46. data/spec/hashie/clash_spec.rb +0 -48
  47. data/spec/hashie/dash_spec.rb +0 -513
  48. data/spec/hashie/extensions/autoload_spec.rb +0 -24
  49. data/spec/hashie/extensions/coercion_spec.rb +0 -625
  50. data/spec/hashie/extensions/dash/coercion_spec.rb +0 -13
  51. data/spec/hashie/extensions/dash/indifferent_access_spec.rb +0 -84
  52. data/spec/hashie/extensions/deep_fetch_spec.rb +0 -97
  53. data/spec/hashie/extensions/deep_find_spec.rb +0 -45
  54. data/spec/hashie/extensions/deep_locate_spec.rb +0 -124
  55. data/spec/hashie/extensions/deep_merge_spec.rb +0 -65
  56. data/spec/hashie/extensions/ignore_undeclared_spec.rb +0 -46
  57. data/spec/hashie/extensions/indifferent_access_spec.rb +0 -219
  58. data/spec/hashie/extensions/indifferent_access_with_rails_hwia_spec.rb +0 -208
  59. data/spec/hashie/extensions/key_conversion_spec.rb +0 -12
  60. data/spec/hashie/extensions/mash/safe_assignment_spec.rb +0 -50
  61. data/spec/hashie/extensions/merge_initializer_spec.rb +0 -23
  62. data/spec/hashie/extensions/method_access_spec.rb +0 -184
  63. data/spec/hashie/extensions/strict_key_access_spec.rb +0 -110
  64. data/spec/hashie/extensions/stringify_keys_spec.rb +0 -124
  65. data/spec/hashie/extensions/symbolize_keys_spec.rb +0 -129
  66. data/spec/hashie/hash_spec.rb +0 -84
  67. data/spec/hashie/mash_spec.rb +0 -680
  68. data/spec/hashie/parsers/yaml_erb_parser_spec.rb +0 -29
  69. data/spec/hashie/rash_spec.rb +0 -77
  70. data/spec/hashie/trash_spec.rb +0 -268
  71. data/spec/hashie/version_spec.rb +0 -7
  72. data/spec/spec_helper.rb +0 -16
  73. data/spec/support/module_context.rb +0 -11
@@ -1,84 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Hashie::Extensions::Dash::IndifferentAccess do
4
- class TrashWithIndifferentAccess < Hashie::Trash
5
- include Hashie::Extensions::Dash::IndifferentAccess
6
- property :per_page, transform_with: ->(v) { v.to_i }
7
- property :total, from: :total_pages
8
- end
9
-
10
- class DashWithIndifferentAccess < Hashie::Dash
11
- include Hashie::Extensions::Dash::IndifferentAccess
12
- property :name
13
- end
14
-
15
- context 'when included in Trash' do
16
- let(:params) { { per_page: '1', total_pages: 2 } }
17
- subject { TrashWithIndifferentAccess.new(params) }
18
-
19
- it 'gets the expected behaviour' do
20
- expect(subject.per_page).to eq params[:per_page].to_i
21
- expect(subject.total).to eq params[:total_pages]
22
- end
23
- end
24
-
25
- context 'when included in Dash' do
26
- let(:patch) { Hashie::Extensions::Dash::IndifferentAccess::ClassMethods }
27
- let(:dash_class) { Class.new(Hashie::Dash) }
28
-
29
- it 'extends with the patch once' do
30
- expect(patch).to receive(:extended).with(dash_class).once
31
- dash_class.send(:include, Hashie::Extensions::Dash::IndifferentAccess)
32
- end
33
- end
34
-
35
- context 'initialized with' do
36
- it 'string' do
37
- instance = DashWithIndifferentAccess.new('name' => 'Name')
38
- expect(instance.name).to eq('Name')
39
- expect(instance['name']).to eq('Name')
40
- expect(instance[:name]).to eq('Name')
41
- expect(instance.inspect).to eq('#<DashWithIndifferentAccess name="Name">')
42
- expect(instance.to_hash).to eq('name' => 'Name')
43
- end
44
-
45
- it 'key' do
46
- instance = DashWithIndifferentAccess.new(name: 'Name')
47
- expect(instance.name).to eq('Name')
48
- expect(instance['name']).to eq('Name')
49
- expect(instance[:name]).to eq('Name')
50
- expect(instance.inspect).to eq('#<DashWithIndifferentAccess name="Name">')
51
- expect(instance.to_hash).to eq('name' => 'Name')
52
- end
53
- end
54
-
55
- it 'updates' do
56
- instance = DashWithIndifferentAccess.new
57
- instance['name'] = 'Updated String'
58
- expect(instance.name).to eq('Updated String')
59
- instance[:name] = 'Updated Symbol'
60
- expect(instance.name).to eq('Updated Symbol')
61
- instance.name = 'Updated Method'
62
- expect(instance.name).to eq('Updated Method')
63
- end
64
-
65
- context 'initialized with both prefers last assignment' do
66
- it 'string, then symbol' do
67
- instance = DashWithIndifferentAccess.new('name' => 'First', name: 'Last')
68
- expect(instance.name).to eq('Last')
69
- expect(instance['name']).to eq('Last')
70
- expect(instance[:name]).to eq('Last')
71
- expect(instance.inspect).to eq('#<DashWithIndifferentAccess name="Last">')
72
- expect(instance.to_hash).to eq('name' => 'Last')
73
- end
74
-
75
- it 'symbol then string' do
76
- instance = DashWithIndifferentAccess.new(name: 'Last', 'name' => 'First')
77
- expect(instance.name).to eq('First')
78
- expect(instance['name']).to eq('First')
79
- expect(instance[:name]).to eq('First')
80
- expect(instance.inspect).to eq('#<DashWithIndifferentAccess name="First">')
81
- expect(instance.to_hash).to eq('name' => 'First')
82
- end
83
- end
84
- end
@@ -1,97 +0,0 @@
1
- require 'spec_helper'
2
-
3
- module Hashie
4
- module Extensions
5
- describe DeepFetch do
6
- subject { Class.new(Hash) { include Hashie::Extensions::DeepFetch } }
7
- let(:hash) do
8
- {
9
- library: {
10
- books: [
11
- { title: 'Call of the Wild' },
12
- { title: 'Moby Dick' }
13
- ],
14
- shelves: nil,
15
- location: {
16
- address: '123 Library St.'
17
- }
18
- }
19
- }
20
- end
21
- let(:instance) { subject.new.update(hash) }
22
-
23
- describe '#deep_fetch' do
24
- it 'extracts a value from a nested hash' do
25
- expect(instance.deep_fetch(:library, :location, :address)).to eq('123 Library St.')
26
- end
27
-
28
- it 'extracts a value from a nested array' do
29
- expect(instance.deep_fetch(:library, :books, 1, :title)).to eq('Moby Dick')
30
- end
31
-
32
- context 'when one of the keys is not present' do
33
- context 'when a block is provided' do
34
- it 'returns the value of the block' do
35
- value = instance.deep_fetch(:library, :unknown_key, :location) { 'block value' }
36
- expect(value).to eq('block value')
37
- end
38
- end
39
-
40
- context 'when a block is not provided' do
41
- context 'when the nested object is an array' do
42
- it 'raises an UndefinedPathError' do
43
- expect do
44
- instance.deep_fetch(:library, :books, 2)
45
- end.to(
46
- raise_error(
47
- DeepFetch::UndefinedPathError,
48
- 'Could not fetch path (library > books > 2) at 2'
49
- )
50
- )
51
- end
52
- end
53
-
54
- context 'when the nested object is a hash' do
55
- it 'raises a UndefinedPathError' do
56
- expect do
57
- instance.deep_fetch(:library, :location, :unknown_key)
58
- end.to(
59
- raise_error(
60
- DeepFetch::UndefinedPathError,
61
- 'Could not fetch path (library > location > unknown_key) at unknown_key'
62
- )
63
- )
64
- end
65
- end
66
-
67
- context 'when the nested object is missing' do
68
- it 'raises an UndefinedPathError' do
69
- expect do
70
- instance.deep_fetch(:library, :unknown_key, :books)
71
- end.to(
72
- raise_error(
73
- DeepFetch::UndefinedPathError,
74
- 'Could not fetch path (library > unknown_key > books) at unknown_key'
75
- )
76
- )
77
- end
78
- end
79
-
80
- context 'when the nested object is nil' do
81
- it 'raises an UndefinedPathError' do
82
- expect do
83
- instance.deep_fetch(:library, :shelves, :address)
84
- end.to(
85
- raise_error(
86
- DeepFetch::UndefinedPathError,
87
- 'Could not fetch path (library > shelves > address) at address'
88
- )
89
- )
90
- end
91
- end
92
- end
93
- end
94
- end
95
- end
96
- end
97
- end
@@ -1,45 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Hashie::Extensions::DeepFind do
4
- subject { Class.new(Hash) { include Hashie::Extensions::DeepFind } }
5
- let(:hash) do
6
- {
7
- library: {
8
- books: [
9
- { title: 'Call of the Wild' },
10
- { title: 'Moby Dick' }
11
- ],
12
- shelves: nil,
13
- location: {
14
- address: '123 Library St.',
15
- title: 'Main Library'
16
- }
17
- }
18
- }
19
- end
20
- let(:instance) { subject.new.update(hash) }
21
-
22
- describe '#deep_find' do
23
- it 'detects a value from a nested hash' do
24
- expect(instance.deep_find(:address)).to eq('123 Library St.')
25
- end
26
-
27
- it 'detects a value from a nested array' do
28
- expect(instance.deep_find(:title)).to eq('Call of the Wild')
29
- end
30
-
31
- it 'returns nil if it does not find a match' do
32
- expect(instance.deep_find(:wahoo)).to be_nil
33
- end
34
- end
35
-
36
- describe '#deep_find_all' do
37
- it 'detects all values from a nested hash' do
38
- expect(instance.deep_find_all(:title)).to eq(['Call of the Wild', 'Moby Dick', 'Main Library'])
39
- end
40
-
41
- it 'returns nil if it does not find any matches' do
42
- expect(instance.deep_find_all(:wahoo)).to be_nil
43
- end
44
- end
45
- end
@@ -1,124 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Hashie::Extensions::DeepLocate do
4
- let(:hash) do
5
- {
6
- from: 0,
7
- size: 25,
8
- query: {
9
- bool: {
10
- must: [
11
- {
12
- query_string: {
13
- query: 'foobar',
14
- default_operator: 'AND',
15
- fields: [
16
- 'title^2',
17
- '_all'
18
- ]
19
- }
20
- },
21
- {
22
- match: {
23
- field_1: 'value_1'
24
- }
25
- },
26
- {
27
- range: {
28
- lsr09: {
29
- gte: 2014
30
- }
31
- }
32
- }
33
- ],
34
- should: [
35
- {
36
- match: {
37
- field_2: 'value_2'
38
- }
39
- }
40
- ],
41
- must_not: [
42
- {
43
- range: {
44
- lsr10: {
45
- gte: 2014
46
- }
47
- }
48
- }
49
- ]
50
- }
51
- }
52
- }
53
- end
54
-
55
- describe '.deep_locate' do
56
- context 'if called with a non-callable comparator' do
57
- it 'creates a key comparator on-th-fly' do
58
- expect(described_class.deep_locate(:lsr10, hash)).to eq([hash[:query][:bool][:must_not][0][:range]])
59
- end
60
- end
61
-
62
- it 'locates enumerables for which the given comparator returns true for at least one element' do
63
- examples = [
64
- [
65
- ->(key, _value, _object) { key == :fields },
66
- [
67
- hash[:query][:bool][:must].first[:query_string]
68
- ]
69
- ],
70
- [
71
- ->(_key, value, _object) { value.is_a?(String) && value.include?('value') },
72
- [
73
- hash[:query][:bool][:must][1][:match],
74
- hash[:query][:bool][:should][0][:match]
75
- ]
76
- ],
77
- [
78
- lambda do |_key, _value, object|
79
- object.is_a?(Array) &&
80
- !object.extend(described_class).deep_locate(:match).empty?
81
- end,
82
- [
83
- hash[:query][:bool][:must],
84
- hash[:query][:bool][:should]
85
- ]
86
- ]
87
- ]
88
-
89
- examples.each do |comparator, expected_result|
90
- expect(described_class.deep_locate(comparator, hash)).to eq(expected_result)
91
- end
92
- end
93
-
94
- it 'returns an empty array if nothing was found' do
95
- expect(described_class.deep_locate(:muff, foo: 'bar')).to eq([])
96
- end
97
- end
98
-
99
- context 'if extending an existing object' do
100
- let(:extended_hash) do
101
- hash.extend(described_class)
102
- end
103
-
104
- it 'adds #deep_locate' do
105
- expect(extended_hash.deep_locate(:bool)).to eq([hash[:query]])
106
- end
107
- end
108
-
109
- context 'if included in a hash' do
110
- let(:derived_hash_with_extension_included) do
111
- Class.new(Hash) do
112
- include Hashie::Extensions::DeepLocate
113
- end
114
- end
115
-
116
- let(:instance) do
117
- derived_hash_with_extension_included.new.update(hash)
118
- end
119
-
120
- it 'adds #deep_locate' do
121
- expect(instance.deep_locate(:bool)).to eq([hash[:query]])
122
- end
123
- end
124
- end
@@ -1,65 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Hashie::Extensions::DeepMerge do
4
- class DeepMergeHash < Hash
5
- include Hashie::Extensions::DeepMerge
6
- end
7
-
8
- subject { DeepMergeHash }
9
-
10
- it 'should return initial hash for arguments that are not hash' do
11
- hash = subject.new.merge(a: 'a')
12
- expect(hash.deep_merge('abc')).to eq(hash)
13
- end
14
-
15
- context 'without &block' do
16
- let(:h1) { subject.new.merge(a: 'a', a1: 42, b: 'b', c: { c1: 'c1', c2: { a: 'b' }, c3: { d1: 'd1' } }) }
17
- let(:h2) { { a: 1, a1: 1, c: { c1: 2, c2: 'c2', c3: { d2: 'd2' } } } }
18
- let(:expected_hash) { { a: 1, a1: 1, b: 'b', c: { c1: 2, c2: 'c2', c3: { d1: 'd1', d2: 'd2' } } } }
19
-
20
- it 'deep merges two hashes' do
21
- expect(h1.deep_merge(h2)).to eq expected_hash
22
- end
23
-
24
- it 'deep merges another hash in place via bang method' do
25
- h1.deep_merge!(h2)
26
- expect(h1).to eq expected_hash
27
- end
28
- end
29
-
30
- context 'with &block' do
31
- let(:h1) { subject.new.merge(a: 100, b: 200, c: { c1: 100 }) }
32
- let(:h2) { { b: 250, c: { c1: 200 } } }
33
- let(:expected_hash) { { a: 100, b: 450, c: { c1: 300 } } }
34
- let(:block) { proc { |_, this_val, other_val| this_val + other_val } }
35
-
36
- it 'deep merges two hashes' do
37
- expect(h1.deep_merge(h2, &block)).to eq expected_hash
38
- end
39
-
40
- it 'deep merges another hash in place via bang method' do
41
- h1.deep_merge!(h2, &block)
42
- expect(h1).to eq expected_hash
43
- end
44
- end
45
-
46
- context 'from extended object' do
47
- subject { Hash }
48
- let(:h1) { subject.new.merge(a: 100, c: { c1: 100 }).extend(Hashie::Extensions::DeepMerge) }
49
- let(:h2) { { b: 250, c: { c1: 200 } } }
50
- let(:expected_hash) { { a: 100, b: 250, c: { c1: 200 } } }
51
-
52
- it 'does not raise error' do
53
- expect { h1.deep_merge(h2) } .not_to raise_error
54
- end
55
-
56
- it 'deep merges two hashes' do
57
- expect(h1.deep_merge(h2)).to eq expected_hash
58
- end
59
-
60
- it 'deep merges another hash in place via bang method' do
61
- h1.deep_merge!(h2)
62
- expect(h1).to eq expected_hash
63
- end
64
- end
65
- end
@@ -1,46 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Hashie::Extensions::IgnoreUndeclared do
4
- context 'included in Trash' do
5
- class ForgivingTrash < Hashie::Trash
6
- include Hashie::Extensions::IgnoreUndeclared
7
- property :city
8
- property :state, from: :provence
9
- end
10
-
11
- subject { ForgivingTrash }
12
-
13
- it 'silently ignores undeclared properties on initialization' do
14
- expect { subject.new(city: 'Toronto', provence: 'ON', country: 'Canada') }.to_not raise_error
15
- end
16
-
17
- it 'works with translated properties (with symbol keys)' do
18
- expect(subject.new(provence: 'Ontario').state).to eq('Ontario')
19
- end
20
-
21
- it 'works with translated properties (with string keys)' do
22
- expect(subject.new(provence: 'Ontario').state).to eq('Ontario')
23
- end
24
-
25
- it 'requires properties to be declared on assignment' do
26
- hash = subject.new(city: 'Toronto')
27
- expect { hash.country = 'Canada' }.to raise_error(NoMethodError)
28
- end
29
- end
30
-
31
- context 'combined with DeepMerge' do
32
- class ForgivingTrashWithMerge < Hashie::Trash
33
- include Hashie::Extensions::DeepMerge
34
- include Hashie::Extensions::IgnoreUndeclared
35
- property :some_key
36
- end
37
-
38
- it 'deep merges' do
39
- class ForgivingTrashWithMergeAndProperty < ForgivingTrashWithMerge
40
- property :some_other_key
41
- end
42
- hash = ForgivingTrashWithMergeAndProperty.new(some_ignored_key: 17, some_key: 12)
43
- expect(hash.deep_merge(some_other_key: 55, some_ignored_key: 18)).to eq(some_key: 12, some_other_key: 55)
44
- end
45
- end
46
- end
@@ -1,219 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Hashie::Extensions::IndifferentAccess do
4
- class IndifferentHashWithMergeInitializer < Hash
5
- include Hashie::Extensions::MergeInitializer
6
- include Hashie::Extensions::IndifferentAccess
7
-
8
- class << self
9
- alias_method :build, :new
10
- end
11
- end
12
-
13
- class IndifferentHashWithArrayInitializer < Hash
14
- include Hashie::Extensions::IndifferentAccess
15
-
16
- class << self
17
- alias_method :build, :[]
18
- end
19
- end
20
-
21
- class IndifferentHashWithTryConvertInitializer < Hash
22
- include Hashie::Extensions::IndifferentAccess
23
-
24
- class << self
25
- alias_method :build, :try_convert
26
- end
27
- end
28
-
29
- class IndifferentHashWithDash < Hashie::Dash
30
- include Hashie::Extensions::IndifferentAccess
31
- property :foo
32
- end
33
-
34
- describe 'when included in dash' do
35
- let(:params) { { foo: 'bar' } }
36
- subject { IndifferentHashWithDash.new(params) }
37
-
38
- it 'initialize with a symbol' do
39
- expect(subject.foo).to eq params[:foo]
40
- end
41
- end
42
-
43
- shared_examples_for 'hash with indifferent access' do
44
- it 'is able to access via string or symbol' do
45
- h = subject.build(abc: 123)
46
- expect(h[:abc]).to eq 123
47
- expect(h['abc']).to eq 123
48
- end
49
-
50
- describe '#values_at' do
51
- it 'indifferently finds values' do
52
- h = subject.build(:foo => 'bar', 'baz' => 'qux')
53
- expect(h.values_at('foo', :baz)).to eq %w(bar qux)
54
- end
55
-
56
- it 'returns the same instance of the hash that was set' do
57
- hash = Hash.new
58
- h = subject.build(foo: hash)
59
- expect(h.values_at(:foo)[0]).to be(hash)
60
- end
61
-
62
- it 'returns the same instance of the array that was set' do
63
- array = Array.new
64
- h = subject.build(foo: array)
65
- expect(h.values_at(:foo)[0]).to be(array)
66
- end
67
-
68
- it 'returns the same instance of the string that was set' do
69
- str = 'my string'
70
- h = subject.build(foo: str)
71
- expect(h.values_at(:foo)[0]).to be(str)
72
- end
73
-
74
- it 'returns the same instance of the object that was set' do
75
- object = Object.new
76
- h = subject.build(foo: object)
77
- expect(h.values_at(:foo)[0]).to be(object)
78
- end
79
- end
80
-
81
- describe '#fetch' do
82
- it 'works like normal fetch, but indifferent' do
83
- h = subject.build(foo: 'bar')
84
- expect(h.fetch(:foo)).to eq h.fetch('foo')
85
- expect(h.fetch(:foo)).to eq 'bar'
86
- end
87
-
88
- it 'returns the same instance of the hash that was set' do
89
- hash = Hash.new
90
- h = subject.build(foo: hash)
91
- expect(h.fetch(:foo)).to be(hash)
92
- end
93
-
94
- it 'returns the same instance of the array that was set' do
95
- array = Array.new
96
- h = subject.build(foo: array)
97
- expect(h.fetch(:foo)).to be(array)
98
- end
99
-
100
- it 'returns the same instance of the string that was set' do
101
- str = 'my string'
102
- h = subject.build(foo: str)
103
- expect(h.fetch(:foo)).to be(str)
104
- end
105
-
106
- it 'returns the same instance of the object that was set' do
107
- object = Object.new
108
- h = subject.build(foo: object)
109
- expect(h.fetch(:foo)).to be(object)
110
- end
111
-
112
- it 'yields with key name if key does not exists' do
113
- h = subject.build(a: 0)
114
- expect(h.fetch(:foo) { |key| ['default for', key] }).to eq ['default for', 'foo']
115
- end
116
- end
117
-
118
- describe '#delete' do
119
- it 'deletes indifferently' do
120
- h = subject.build(:foo => 'bar', 'baz' => 'qux')
121
- h.delete('foo')
122
- h.delete(:baz)
123
- expect(h).to be_empty
124
- end
125
- end
126
-
127
- describe '#key?' do
128
- let(:h) { subject.build(foo: 'bar') }
129
-
130
- it 'finds it indifferently' do
131
- expect(h).to be_key(:foo)
132
- expect(h).to be_key('foo')
133
- end
134
-
135
- %w(include? member? has_key?).each do |key_alias|
136
- it "is aliased as #{key_alias}" do
137
- expect(h.send(key_alias.to_sym, :foo)).to be(true)
138
- expect(h.send(key_alias.to_sym, 'foo')).to be(true)
139
- end
140
- end
141
- end
142
-
143
- describe '#update' do
144
- let(:h) { subject.build(foo: 'bar') }
145
-
146
- it 'allows keys to be indifferent still' do
147
- h.update(baz: 'qux')
148
- expect(h['foo']).to eq 'bar'
149
- expect(h['baz']).to eq 'qux'
150
- end
151
-
152
- it 'recursively injects indifference into sub-hashes' do
153
- h.update(baz: { qux: 'abc' })
154
- expect(h['baz']['qux']).to eq 'abc'
155
- end
156
-
157
- it 'does not change the ancestors of the injected object class' do
158
- h.update(baz: { qux: 'abc' })
159
- expect(Hash.new).not_to be_respond_to(:indifferent_access?)
160
- end
161
- end
162
-
163
- describe '#replace' do
164
- let(:h) { subject.build(foo: 'bar').replace(bar: 'baz', hi: 'bye') }
165
-
166
- it 'returns self' do
167
- expect(h).to be_a(subject)
168
- end
169
-
170
- it 'removes old keys' do
171
- [:foo, 'foo'].each do |k|
172
- expect(h[k]).to be_nil
173
- expect(h.key?(k)).to be_falsy
174
- end
175
- end
176
-
177
- it 'creates new keys with indifferent access' do
178
- [:bar, 'bar', :hi, 'hi'].each { |k| expect(h.key?(k)).to be_truthy }
179
- expect(h[:bar]).to eq 'baz'
180
- expect(h['bar']).to eq 'baz'
181
- expect(h[:hi]).to eq 'bye'
182
- expect(h['hi']).to eq 'bye'
183
- end
184
- end
185
-
186
- describe '#try_convert' do
187
- describe 'with conversion' do
188
- let(:h) { subject.try_convert(foo: 'bar') }
189
-
190
- it 'is a subject' do
191
- expect(h).to be_a(subject)
192
- end
193
- end
194
-
195
- describe 'without conversion' do
196
- let(:h) { subject.try_convert('{ :foo => bar }') }
197
-
198
- it 'is nil' do
199
- expect(h).to be_nil
200
- end
201
- end
202
- end
203
- end
204
-
205
- describe 'with merge initializer' do
206
- subject { IndifferentHashWithMergeInitializer }
207
- it_should_behave_like 'hash with indifferent access'
208
- end
209
-
210
- describe 'with array initializer' do
211
- subject { IndifferentHashWithArrayInitializer }
212
- it_should_behave_like 'hash with indifferent access'
213
- end
214
-
215
- describe 'with try convert initializer' do
216
- subject { IndifferentHashWithTryConvertInitializer }
217
- it_should_behave_like 'hash with indifferent access'
218
- end
219
- end