hashie 3.6.0 → 4.1.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 (78) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +228 -174
  3. data/CONTRIBUTING.md +13 -6
  4. data/README.md +127 -15
  5. data/UPGRADING.md +83 -7
  6. data/hashie.gemspec +13 -7
  7. data/lib/hashie.rb +21 -19
  8. data/lib/hashie/dash.rb +2 -1
  9. data/lib/hashie/extensions/active_support/core_ext/hash.rb +14 -0
  10. data/lib/hashie/extensions/coercion.rb +23 -16
  11. data/lib/hashie/extensions/dash/indifferent_access.rb +20 -1
  12. data/lib/hashie/extensions/dash/property_translation.rb +6 -3
  13. data/lib/hashie/extensions/deep_fetch.rb +4 -2
  14. data/lib/hashie/extensions/deep_find.rb +12 -3
  15. data/lib/hashie/extensions/deep_locate.rb +22 -7
  16. data/lib/hashie/extensions/deep_merge.rb +18 -1
  17. data/lib/hashie/extensions/indifferent_access.rb +1 -3
  18. data/lib/hashie/extensions/key_conflict_warning.rb +55 -0
  19. data/lib/hashie/extensions/mash/define_accessors.rb +90 -0
  20. data/lib/hashie/extensions/mash/keep_original_keys.rb +2 -1
  21. data/lib/hashie/extensions/mash/permissive_respond_to.rb +61 -0
  22. data/lib/hashie/extensions/mash/safe_assignment.rb +3 -1
  23. data/lib/hashie/extensions/method_access.rb +5 -2
  24. data/lib/hashie/extensions/parsers/yaml_erb_parser.rb +26 -4
  25. data/lib/hashie/extensions/ruby_version_check.rb +5 -1
  26. data/lib/hashie/extensions/strict_key_access.rb +8 -4
  27. data/lib/hashie/hash.rb +16 -9
  28. data/lib/hashie/mash.rb +114 -53
  29. data/lib/hashie/railtie.rb +7 -0
  30. data/lib/hashie/rash.rb +1 -1
  31. data/lib/hashie/utils.rb +28 -0
  32. data/lib/hashie/version.rb +1 -1
  33. metadata +19 -130
  34. data/spec/hashie/array_spec.rb +0 -29
  35. data/spec/hashie/clash_spec.rb +0 -70
  36. data/spec/hashie/dash_spec.rb +0 -598
  37. data/spec/hashie/extensions/autoload_spec.rb +0 -24
  38. data/spec/hashie/extensions/coercion_spec.rb +0 -639
  39. data/spec/hashie/extensions/dash/coercion_spec.rb +0 -13
  40. data/spec/hashie/extensions/dash/indifferent_access_spec.rb +0 -84
  41. data/spec/hashie/extensions/deep_fetch_spec.rb +0 -97
  42. data/spec/hashie/extensions/deep_find_spec.rb +0 -138
  43. data/spec/hashie/extensions/deep_locate_spec.rb +0 -137
  44. data/spec/hashie/extensions/deep_merge_spec.rb +0 -70
  45. data/spec/hashie/extensions/ignore_undeclared_spec.rb +0 -47
  46. data/spec/hashie/extensions/indifferent_access_spec.rb +0 -295
  47. data/spec/hashie/extensions/indifferent_access_with_rails_hwia_spec.rb +0 -208
  48. data/spec/hashie/extensions/key_conversion_spec.rb +0 -12
  49. data/spec/hashie/extensions/mash/keep_original_keys_spec.rb +0 -46
  50. data/spec/hashie/extensions/mash/safe_assignment_spec.rb +0 -50
  51. data/spec/hashie/extensions/mash/symbolize_keys_spec.rb +0 -39
  52. data/spec/hashie/extensions/merge_initializer_spec.rb +0 -23
  53. data/spec/hashie/extensions/method_access_spec.rb +0 -226
  54. data/spec/hashie/extensions/strict_key_access_spec.rb +0 -110
  55. data/spec/hashie/extensions/stringify_keys_spec.rb +0 -124
  56. data/spec/hashie/extensions/symbolize_keys_spec.rb +0 -129
  57. data/spec/hashie/hash_spec.rb +0 -84
  58. data/spec/hashie/mash_spec.rb +0 -771
  59. data/spec/hashie/parsers/yaml_erb_parser_spec.rb +0 -46
  60. data/spec/hashie/rash_spec.rb +0 -83
  61. data/spec/hashie/trash_spec.rb +0 -328
  62. data/spec/hashie/utils_spec.rb +0 -25
  63. data/spec/hashie/version_spec.rb +0 -7
  64. data/spec/hashie_spec.rb +0 -13
  65. data/spec/integration/elasticsearch/integration_spec.rb +0 -40
  66. data/spec/integration/omniauth-oauth2/app.rb +0 -52
  67. data/spec/integration/omniauth-oauth2/integration_spec.rb +0 -26
  68. data/spec/integration/omniauth-oauth2/some_site.rb +0 -38
  69. data/spec/integration/omniauth/app.rb +0 -11
  70. data/spec/integration/omniauth/integration_spec.rb +0 -38
  71. data/spec/integration/rails-without-dependency/integration_spec.rb +0 -15
  72. data/spec/integration/rails/app.rb +0 -47
  73. data/spec/integration/rails/integration_spec.rb +0 -26
  74. data/spec/spec_helper.rb +0 -23
  75. data/spec/support/integration_specs.rb +0 -36
  76. data/spec/support/logger.rb +0 -24
  77. data/spec/support/module_context.rb +0 -11
  78. data/spec/support/ruby_version_check.rb +0 -6
@@ -1,12 +0,0 @@
1
- require 'spec_helper'
2
- require 'support/module_context'
3
-
4
- describe Hashie::Extensions::KeyConversion do
5
- include_context 'included hash module'
6
-
7
- it { should respond_to(:stringify_keys) }
8
- it { should respond_to(:stringify_keys!) }
9
-
10
- it { should respond_to(:symbolize_keys) }
11
- it { should respond_to(:symbolize_keys!) }
12
- end
@@ -1,46 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe Hashie::Extensions::Mash::KeepOriginalKeys do
4
- let(:keeping_mash) do
5
- Class.new(Hashie::Mash) do
6
- include Hashie::Extensions::Mash::KeepOriginalKeys
7
- end
8
- end
9
-
10
- it 'keeps the keys in the resulting hash identical to the original' do
11
- original = { :a => 'apple', 'b' => 'bottle' }
12
- mash = keeping_mash.new(original)
13
-
14
- expect(mash.to_hash).to eq(original)
15
- end
16
-
17
- it 'indifferently responds to keys' do
18
- original = { :a => 'apple', 'b' => 'bottle' }
19
- mash = keeping_mash.new(original)
20
-
21
- expect(mash['a']).to eq(mash[:a])
22
- expect(mash['b']).to eq(mash[:b])
23
- end
24
-
25
- it 'responds to all method accessors like a Mash' do
26
- original = { :a => 'apple', 'b' => 'bottle' }
27
- mash = keeping_mash.new(original)
28
-
29
- expect(mash.a).to eq('apple')
30
- expect(mash.a?).to eq(true)
31
- expect(mash.b).to eq('bottle')
32
- expect(mash.b?).to eq(true)
33
- expect(mash.underbang_).to be_a(keeping_mash)
34
- expect(mash.bang!).to be_a(keeping_mash)
35
- expect(mash.predicate?).to eq(false)
36
- end
37
-
38
- it 'keeps the keys that are directly passed without converting them' do
39
- original = { :a => 'apple', 'b' => 'bottle' }
40
- mash = keeping_mash.new(original)
41
-
42
- mash[:c] = 'cat'
43
- mash['d'] = 'dog'
44
- expect(mash.to_hash).to eq(:a => 'apple', 'b' => 'bottle', :c => 'cat', 'd' => 'dog')
45
- end
46
- end
@@ -1,50 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Hashie::Extensions::Mash::SafeAssignment do
4
- class MashWithSafeAssignment < Hashie::Mash
5
- include Hashie::Extensions::Mash::SafeAssignment
6
-
7
- private
8
-
9
- def my_own_private
10
- :hello!
11
- end
12
- end
13
-
14
- context 'when included in Mash' do
15
- subject { MashWithSafeAssignment.new }
16
-
17
- context 'when not attempting to override a method' do
18
- it 'assigns just fine' do
19
- expect do
20
- subject.blabla = 'Test'
21
- subject.blabla = 'Test'
22
- end.to_not raise_error
23
- end
24
- end
25
-
26
- context 'when attempting to override a method' do
27
- it 'raises an error' do
28
- expect { subject.zip = 'Test' }.to raise_error(ArgumentError)
29
- end
30
- end
31
-
32
- context 'when attempting to override a private method' do
33
- it 'raises an error' do
34
- expect { subject.my_own_private = 'Test' }.to raise_error(ArgumentError)
35
- end
36
- end
37
-
38
- context 'when attempting to initialize with predefined method' do
39
- it 'raises an error' do
40
- expect { MashWithSafeAssignment.new(zip: true) }.to raise_error(ArgumentError)
41
- end
42
- end
43
-
44
- context 'when setting as a hash key' do
45
- it 'still raises if conflicts with a method' do
46
- expect { subject[:zip] = 'Test' }.to raise_error(ArgumentError)
47
- end
48
- end
49
- end
50
- end
@@ -1,39 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe Hashie::Extensions::Mash::SymbolizeKeys do
4
- it 'raises an error when included in a class that is not a Mash' do
5
- expect do
6
- Class.new do
7
- include Hashie::Extensions::Mash::SymbolizeKeys
8
- end
9
- end.to raise_error(ArgumentError)
10
- end
11
-
12
- it 'symbolizes all keys in the Mash' do
13
- my_mash = Class.new(Hashie::Mash) do
14
- include Hashie::Extensions::Mash::SymbolizeKeys
15
- end
16
-
17
- expect(my_mash.new('test' => 'value').to_h).to eq(test: 'value')
18
- end
19
-
20
- context 'implicit to_hash on double splat' do
21
- let(:destructure) { ->(**opts) { opts } }
22
- let(:my_mash) do
23
- Class.new(Hashie::Mash) do
24
- include Hashie::Extensions::Mash::SymbolizeKeys
25
- end
26
- end
27
- let(:instance) { my_mash.new('outer' => { 'inner' => 42 }, 'testing' => [1, 2, 3]) }
28
-
29
- subject { destructure.call(instance) }
30
-
31
- it 'is converted on method calls' do
32
- expect(subject).to eq(outer: { inner: 42 }, testing: [1, 2, 3])
33
- end
34
-
35
- it 'is converted on explicit operator call' do
36
- expect(**instance).to eq(outer: { inner: 42 }, testing: [1, 2, 3])
37
- end
38
- end
39
- end
@@ -1,23 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Hashie::Extensions::MergeInitializer do
4
- class MergeInitializerHash < Hash
5
- include Hashie::Extensions::MergeInitializer
6
- end
7
-
8
- subject { MergeInitializerHash }
9
-
10
- it 'initializes with no arguments' do
11
- expect(subject.new).to eq({})
12
- end
13
-
14
- it 'initializes with a hash' do
15
- expect(subject.new(abc: 'def')).to eq(abc: 'def')
16
- end
17
-
18
- it 'initializes with a hash and a default' do
19
- h = subject.new({ abc: 'def' }, 'bar')
20
- expect(h[:foo]).to eq 'bar'
21
- expect(h[:abc]).to eq 'def'
22
- end
23
- end
@@ -1,226 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Hashie::Extensions::MethodReader do
4
- class ReaderHash < Hash
5
- include Hashie::Extensions::MethodReader
6
-
7
- def initialize(hash = {})
8
- update(hash)
9
- end
10
- end
11
-
12
- subject { ReaderHash }
13
-
14
- it 'reads string keys from the method' do
15
- expect(subject.new('awesome' => 'sauce').awesome).to eq 'sauce'
16
- end
17
-
18
- it 'reads symbol keys from the method' do
19
- expect(subject.new(awesome: 'sauce').awesome).to eq 'sauce'
20
- end
21
-
22
- it 'reads nil and false values out properly' do
23
- h = subject.new(nil: nil, false: false) # rubocop:disable Lint/BooleanSymbol
24
- expect(h.nil).to eq nil
25
- expect(h.false).to eq false
26
- end
27
-
28
- it 'raises a NoMethodError for undefined keys' do
29
- expect { subject.new.awesome }.to raise_error(NoMethodError)
30
- end
31
-
32
- it 'returns false for undefined keys if key with question has been called ' do
33
- expect(subject.new.awesome?).to eq false
34
- end
35
-
36
- it 'returns true for defined keys if key with question has been called' do
37
- expect(subject.new(awesome: 'sauce').awesome?).to eq true
38
- end
39
-
40
- describe '#respond_to?' do
41
- it 'is true for string keys' do
42
- expect(subject.new('awesome' => 'sauce')).to be_respond_to(:awesome)
43
- end
44
-
45
- it 'is true for symbol keys' do
46
- expect(subject.new(awesome: 'sauce')).to be_respond_to(:awesome)
47
- end
48
-
49
- it 'is false for non-keys' do
50
- expect(subject.new).not_to be_respond_to(:awesome)
51
- end
52
- end
53
- end
54
-
55
- describe Hashie::Extensions::MethodWriter do
56
- class WriterHash < Hash
57
- include Hashie::Extensions::MethodWriter
58
- end
59
-
60
- subject { WriterHash.new }
61
-
62
- it 'writes from a method call' do
63
- subject.awesome = 'sauce'
64
- expect(subject['awesome']).to eq 'sauce'
65
- end
66
-
67
- it 'converts the key using the #convert_key method' do
68
- allow(subject).to receive(:convert_key).and_return(:awesome)
69
- subject.awesome = 'sauce'
70
- expect(subject[:awesome]).to eq 'sauce'
71
- end
72
-
73
- it 'raises NoMethodError on non equals-ending methods' do
74
- expect { subject.awesome }.to raise_error(NoMethodError)
75
- end
76
-
77
- it '#respond_to? correctly' do
78
- expect(subject).to be_respond_to(:abc=)
79
- expect(subject).not_to be_respond_to(:abc)
80
- end
81
- end
82
-
83
- describe Hashie::Extensions::MethodQuery do
84
- class QueryHash < Hash
85
- include Hashie::Extensions::MethodQuery
86
-
87
- def initialize(hash = {})
88
- update(hash)
89
- end
90
- end
91
-
92
- subject { QueryHash }
93
-
94
- it 'is true for non-nil string key values' do
95
- expect(subject.new('abc' => 123).abc?).to eq true
96
- end
97
-
98
- it 'is true for non-nil symbol key values' do
99
- expect(subject.new(abc: 123).abc?).to eq true
100
- end
101
-
102
- it 'is false for false key values' do
103
- expect(subject.new(abc: false).abc?).to eq false
104
- end
105
-
106
- it 'is false for nil key values' do
107
- expect(subject.new(abc: nil).abc?).to eq false
108
- end
109
-
110
- it 'raises a NoMethodError for non-set keys' do
111
- expect { subject.new.abc? }.to raise_error(NoMethodError)
112
- end
113
-
114
- it '#respond_to? for existing string keys' do
115
- expect(subject.new('abc' => 'def')).to be_respond_to('abc?')
116
- end
117
-
118
- it '#respond_to? for existing symbol keys' do
119
- expect(subject.new(abc: 'def')).to be_respond_to(:abc?)
120
- end
121
-
122
- it 'does not #respond_to? for non-existent keys' do
123
- expect(subject.new).not_to be_respond_to('abc?')
124
- end
125
- end
126
-
127
- describe Hashie::Extensions::MethodAccess do
128
- it 'includes all of the other method mixins' do
129
- klass = Class.new(Hash)
130
- klass.send :include, Hashie::Extensions::MethodAccess
131
- expect((klass.ancestors & [Hashie::Extensions::MethodReader, Hashie::Extensions::MethodWriter, Hashie::Extensions::MethodQuery]).size).to eq 3
132
- end
133
- end
134
-
135
- describe Hashie::Extensions::MethodOverridingWriter do
136
- class OverridingHash < Hash
137
- include Hashie::Extensions::MethodOverridingWriter
138
- end
139
-
140
- subject { OverridingHash.new }
141
-
142
- it 'writes from a method call' do
143
- subject.awesome = 'sauce'
144
- expect(subject['awesome']).to eq 'sauce'
145
- end
146
-
147
- it 'convertes the key using the #convert_key method' do
148
- allow(subject).to receive(:convert_key).and_return(:awesome)
149
- subject.awesome = 'sauce'
150
- expect(subject[:awesome]).to eq 'sauce'
151
- end
152
-
153
- it 'raises NoMethodError on non equals-ending methods' do
154
- expect { subject.awesome }.to raise_error(NoMethodError)
155
- end
156
-
157
- it '#respond_to_missing? correctly' do
158
- expect(subject).to respond_to(:abc=)
159
- expect(subject).not_to respond_to(:abc)
160
- expect(subject.method(:abc=)).not_to be_nil
161
- end
162
-
163
- context 'when writing a Hash method' do
164
- before { subject.zip = 'a-dee-doo-dah' }
165
-
166
- it 'overrides the original method' do
167
- expect(subject.zip).to eq 'a-dee-doo-dah'
168
- end
169
-
170
- it 'aliases the method with two leading underscores' do
171
- expect(subject.__zip).to eq [[%w[zip a-dee-doo-dah]]]
172
- end
173
-
174
- it 'does not re-alias when overriding an already overridden method' do
175
- subject.zip = 'test'
176
- expect(subject.zip).to eq 'test'
177
- expect(subject.__zip).to eq [[%w[zip test]]]
178
- end
179
- end
180
- end
181
-
182
- describe Hashie::Extensions::MethodAccessWithOverride do
183
- it 'includes all of the other method mixins' do
184
- mod_list = [
185
- Hashie::Extensions::MethodReader,
186
- Hashie::Extensions::MethodOverridingWriter,
187
- Hashie::Extensions::MethodQuery,
188
- Hashie::Extensions::MethodOverridingInitializer
189
- ]
190
-
191
- klass = Class.new(Hash)
192
- klass.send :include, Hashie::Extensions::MethodAccessWithOverride
193
-
194
- expect((klass.ancestors & mod_list).size).to eq 4
195
- end
196
- end
197
-
198
- describe Hashie::Extensions::MethodOverridingInitializer do
199
- class OverridingHash < Hash
200
- include Hashie::Extensions::MethodOverridingInitializer
201
- end
202
-
203
- context 'when the key is a string' do
204
- subject { OverridingHash.new('zip' => 'a-dee-doo-dah') }
205
-
206
- it 'overrides the original method' do
207
- expect(subject.zip).to eq 'a-dee-doo-dah'
208
- end
209
-
210
- it 'aliases the method with two leading underscores' do
211
- expect(subject.__zip).to eq [[%w[zip a-dee-doo-dah]]]
212
- end
213
- end
214
-
215
- context 'when the key is a symbol' do
216
- subject { OverridingHash.new(zip: 'a-dee-doo-dah') }
217
-
218
- it 'overrides the original method' do
219
- expect(subject.zip).to eq 'a-dee-doo-dah'
220
- end
221
-
222
- it 'aliases the method with two leading underscores' do
223
- expect(subject.__zip).to eq [[%w[zip a-dee-doo-dah]]]
224
- end
225
- end
226
- end
@@ -1,110 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Hashie::Extensions::StrictKeyAccess do
4
- class StrictKeyAccessHash < Hash
5
- include Hashie::Extensions::StrictKeyAccess
6
- end
7
-
8
- shared_examples_for 'StrictKeyAccess with valid key' do |options = {}|
9
- before { pending_for(options[:pending]) } if options[:pending]
10
- context 'set' do
11
- let(:new_value) { 42 }
12
- it('returns value') do
13
- expect(instance.send(:[]=, valid_key, new_value)).to eq new_value
14
- end
15
- end
16
- context 'access' do
17
- it('returns value') do
18
- expect(instance[valid_key]).to eq valid_value
19
- end
20
- end
21
- context 'lookup' do
22
- it('returns key') do
23
- expect(instance.key(valid_value)).to eq valid_key
24
- end
25
- end
26
- end
27
- shared_examples_for 'StrictKeyAccess with invalid key' do |options = {}|
28
- before { pending_for(options[:pending]) } if options[:pending]
29
- context 'access' do
30
- it('raises an error') do
31
- # Formatting of the error message varies on Rubinius and ruby-head
32
- expect { instance[invalid_key] }.to raise_error KeyError
33
- end
34
- end
35
- context 'lookup' do
36
- it('raises an error') do
37
- # Formatting of the error message does not vary here because raised by StrictKeyAccess
38
- expect { instance.key(invalid_value) }.to raise_error KeyError,
39
- %(key not found with value of #{invalid_value.inspect})
40
- end
41
- end
42
- end
43
- shared_examples_for 'StrictKeyAccess raises KeyError instead of allowing defaults' do
44
- context '#default' do
45
- it 'raises an error' do
46
- expect { instance.default(invalid_key) }.to raise_error Hashie::Extensions::StrictKeyAccess::DefaultError,
47
- 'Setting or using a default with Hashie::Extensions::StrictKeyAccess does not make sense'
48
- end
49
- end
50
- context '#default=' do
51
- it 'raises an error' do
52
- expect { instance.default = invalid_key }.to raise_error Hashie::Extensions::StrictKeyAccess::DefaultError,
53
- 'Setting or using a default with Hashie::Extensions::StrictKeyAccess does not make sense'
54
- end
55
- end
56
- context '#default_proc' do
57
- it 'raises an error' do
58
- expect { instance.default_proc }.to raise_error Hashie::Extensions::StrictKeyAccess::DefaultError,
59
- 'Setting or using a default with Hashie::Extensions::StrictKeyAccess does not make sense'
60
- end
61
- end
62
- context '#default_proc=' do
63
- it 'raises an error' do
64
- expect { instance.default_proc = proc {} }.to raise_error Hashie::Extensions::StrictKeyAccess::DefaultError,
65
- 'Setting or using a default with Hashie::Extensions::StrictKeyAccess does not make sense'
66
- end
67
- end
68
- end
69
-
70
- let(:klass) { StrictKeyAccessHash }
71
- let(:instance) { StrictKeyAccessHash.new(*initialization_args) }
72
- let(:initialization_args) do
73
- [
74
- { valid_key => valid_value }
75
- ]
76
- end
77
- let(:valid_key) { :abc }
78
- let(:valid_value) { 'def' }
79
- let(:invalid_key) { :mega }
80
- let(:invalid_value) { 'death' }
81
-
82
- context '.new' do
83
- context 'no defaults at initialization' do
84
- let(:initialization_args) { [] }
85
- before do
86
- instance.merge!(valid_key => valid_value)
87
- end
88
- it_behaves_like 'StrictKeyAccess with valid key'
89
- it_behaves_like 'StrictKeyAccess with invalid key'
90
- it_behaves_like 'StrictKeyAccess raises KeyError instead of allowing defaults'
91
- end
92
- context 'with defaults at initialization' do
93
- before do
94
- instance.merge!(valid_key => valid_value)
95
- end
96
- it_behaves_like 'StrictKeyAccess with valid key'
97
- it_behaves_like 'StrictKeyAccess with invalid key'
98
- it_behaves_like 'StrictKeyAccess raises KeyError instead of allowing defaults'
99
- end
100
- it_behaves_like 'StrictKeyAccess with invalid key'
101
- it_behaves_like 'StrictKeyAccess raises KeyError instead of allowing defaults'
102
- end
103
-
104
- context '.[]' do
105
- let(:instance) { StrictKeyAccessHash[*initialization_args] }
106
- it_behaves_like 'StrictKeyAccess with valid key', pending: { engine: 'rbx' }
107
- it_behaves_like 'StrictKeyAccess with invalid key', pending: { engine: 'rbx' }
108
- it_behaves_like 'StrictKeyAccess raises KeyError instead of allowing defaults'
109
- end
110
- end