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,46 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Hashie::Extensions::Parsers::YamlErbParser do
4
- describe '.perform' do
5
- context 'a file' do
6
- let(:config) do
7
- <<-CONFIG
8
- ---
9
- foo: verbatim
10
- bar: <%= "erb" %>
11
- baz: "<%= __FILE__ %>"
12
- CONFIG
13
- end
14
- let(:path) { 'template.yml' }
15
-
16
- subject { described_class.new(path).perform }
17
-
18
- before do
19
- expect(File).to receive(:read).with(path).and_return(config)
20
- end
21
-
22
- it { is_expected.to be_a(Hash) }
23
-
24
- it 'parses YAML after interpolating ERB' do
25
- expect(subject['foo']).to eq 'verbatim'
26
- expect(subject['bar']).to eq 'erb'
27
- expect(subject['baz']).to eq path
28
- end
29
- end
30
-
31
- context 'Pathname' do
32
- let(:tempfile) do
33
- file = Tempfile.new(['foo', '.yml'])
34
- file.write("---\nfoo: hello\n")
35
- file.rewind
36
- file
37
- end
38
-
39
- subject { described_class.new(Pathname(tempfile.path)) }
40
-
41
- it '"#perform" can be done in case of path is a Pathname object.' do
42
- expect(subject.perform).to eq 'foo' => 'hello'
43
- end
44
- end
45
- end
46
- end
@@ -1,83 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Hashie::Rash do
4
- subject do
5
- Hashie::Rash.new(
6
- /hello/ => 'hello',
7
- /world/ => 'world',
8
- 'other' => 'whee',
9
- true => false,
10
- 1 => 'awesome',
11
- 1..1000 => 'rangey',
12
- /(bcd)/ => proc { |m| m[1] }
13
- # /.+/ => "EVERYTHING"
14
- )
15
- end
16
-
17
- it 'finds strings' do
18
- expect(subject['other']).to eq 'whee'
19
- expect(subject['well hello there']).to eq 'hello'
20
- expect(subject['the world is round']).to eq 'world'
21
- expect(subject.all('hello world').sort).to eq %w[hello world]
22
- end
23
-
24
- it 'finds regexps' do
25
- expect(subject[/other/]).to eq 'whee'
26
- end
27
-
28
- it 'finds other objects' do
29
- expect(subject[true]).to eq false
30
- expect(subject[1]).to eq 'awesome'
31
- end
32
-
33
- it 'finds numbers from ranges' do
34
- expect(subject[250]).to eq 'rangey'
35
- expect(subject[999]).to eq 'rangey'
36
- expect(subject[1000]).to eq 'rangey'
37
- expect(subject[1001]).to be_nil
38
- end
39
-
40
- it 'finds floats from ranges' do
41
- expect(subject[10.1]).to eq 'rangey'
42
- expect(subject[1.0]).to eq 'rangey'
43
- expect(subject[1000.1]).to be_nil
44
- end
45
-
46
- it 'evaluates proc values' do
47
- expect(subject['abcdef']).to eq 'bcd'
48
- expect(subject['ffffff']).to be_nil
49
- end
50
-
51
- it 'finds using the find method' do
52
- expect(subject.fetch(10.1)).to eq 'rangey'
53
- expect(subject.fetch(true)).to be false
54
- end
55
-
56
- it 'raises in find unless a key matches' do
57
- expect { subject.fetch(1_000_000) }.to raise_error(KeyError)
58
- end
59
-
60
- it 'yields in find unless a key matches' do
61
- expect { |y| subject.fetch(1_000_000, &y) }.to yield_control
62
- expect { |y| subject.fetch(10.1, &y) }.to_not yield_control
63
- end
64
-
65
- it 'gives a default value' do
66
- expect(subject.fetch(10.1, 'noop')).to eq 'rangey'
67
- expect(subject.fetch(1_000_000, 'noop')).to eq 'noop'
68
- expect(subject.fetch(1_000_000) { 'noop' }).to eq 'noop'
69
- expect(subject.fetch(1_000_000) { |k| k }).to eq 1_000_000
70
- expect(subject.fetch(1_000_000, 'noop') { 'op' }).to eq 'op'
71
- end
72
-
73
- it 'responds to hash methods' do
74
- expect(subject.respond_to?(:to_a)).to be true
75
- expect(subject.methods).to_not include(:to_a)
76
- end
77
-
78
- it 'does not lose keys' do
79
- subject.optimize_every = 1
80
- expect(subject['hello']).to eq('hello')
81
- expect(subject['world']).to eq('world')
82
- end
83
- end
@@ -1,328 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Hashie::Trash do
4
- class TrashTest < Hashie::Trash
5
- property :first_name, from: :firstName
6
- end
7
-
8
- let(:trash) { TrashTest.new }
9
-
10
- describe 'translating properties' do
11
- it 'adds the property to the list' do
12
- expect(TrashTest.properties).to include(:first_name)
13
- end
14
-
15
- it 'creates a method for reading the property' do
16
- expect(trash).to respond_to(:first_name)
17
- end
18
-
19
- it 'creates a method for writing the property' do
20
- expect(trash).to respond_to(:first_name=)
21
- end
22
-
23
- it 'creates a method for writing the translated property' do
24
- expect(trash).to respond_to(:firstName=)
25
- end
26
-
27
- it 'does not create a method for reading the translated property' do
28
- expect(trash).not_to respond_to(:firstName)
29
- end
30
-
31
- it 'maintains translations hash mapping from the original to the translated name' do
32
- expect(TrashTest.translations[:firstName]).to eq(:first_name)
33
- end
34
-
35
- it 'maintains inverse translations hash mapping from the translated to the original name' do
36
- expect(TrashTest.inverse_translations[:first_name]).to eq :firstName
37
- end
38
-
39
- it '#permitted_input_keys contain the :from key of properties with translations' do
40
- expect(TrashTest.permitted_input_keys).to include :firstName
41
- end
42
- end
43
-
44
- describe 'standard properties' do
45
- class TrashTestPermitted < Hashie::Trash
46
- property :id
47
- end
48
-
49
- it '#permitted_input_keys contain names of properties without translations' do
50
- expect(TrashTestPermitted.permitted_input_keys).to include :id
51
- end
52
- end
53
-
54
- describe 'writing to properties' do
55
- it 'does not write to a non-existent property using []=' do
56
- expect { trash['abc'] = 123 }.to raise_error(NoMethodError)
57
- end
58
-
59
- it 'writes to an existing property using []=' do
60
- expect { trash[:first_name] = 'Bob' }.not_to raise_error
61
- expect(trash.first_name).to eq('Bob')
62
- expect { trash['first_name'] = 'John' }.to raise_error(NoMethodError)
63
- end
64
-
65
- it 'writes to a translated property using []=' do
66
- expect { trash[:firstName] = 'Bob' }.not_to raise_error
67
- expect { trash['firstName'] = 'Bob' }.to raise_error(NoMethodError)
68
- end
69
-
70
- it 'reads/writes to an existing property using a method call' do
71
- trash.first_name = 'Franklin'
72
- expect(trash.first_name).to eq 'Franklin'
73
- end
74
-
75
- it 'writes to an translated property using a method call' do
76
- trash.firstName = 'Franklin'
77
- expect(trash.first_name).to eq 'Franklin'
78
- end
79
-
80
- it 'writes to a translated property using #replace' do
81
- trash.replace(firstName: 'Franklin')
82
- expect(trash.first_name).to eq 'Franklin'
83
- end
84
-
85
- it 'writes to a non-translated property using #replace' do
86
- trash.replace(first_name: 'Franklin')
87
- expect(trash.first_name).to eq 'Franklin'
88
- end
89
- end
90
-
91
- describe ' initializing with a Hash' do
92
- it 'does not initialize non-existent properties' do
93
- expect { TrashTest.new(bork: 'abc') }.to raise_error(NoMethodError)
94
- end
95
-
96
- it 'sets the desired properties' do
97
- expect(TrashTest.new(first_name: 'Michael').first_name).to eq 'Michael'
98
- end
99
-
100
- context 'with both the translated property and the property' do
101
- it 'sets the desired properties' do
102
- expect(TrashTest.new(first_name: 'Michael', firstName: 'Maeve').first_name).to eq 'Michael'
103
- end
104
- end
105
-
106
- it 'sets the translated properties' do
107
- expect(TrashTest.new(firstName: 'Michael').first_name).to eq 'Michael'
108
- end
109
- end
110
-
111
- describe 'translating properties using a proc' do
112
- class TrashLambdaTest < Hashie::Trash
113
- property :first_name, from: :firstName, with: ->(value) { value.reverse }
114
- end
115
-
116
- let(:lambda_trash) { TrashLambdaTest.new }
117
-
118
- it 'translates the value given on initialization with the given lambda' do
119
- expect(TrashLambdaTest.new(firstName: 'Michael').first_name).to eq 'Michael'.reverse
120
- end
121
-
122
- it 'does not translate the value if given with the right property' do
123
- expect(TrashTest.new(first_name: 'Michael').first_name).to eq 'Michael'
124
- end
125
-
126
- it 'translates the value given as property with the given lambda' do
127
- lambda_trash.firstName = 'Michael'
128
- expect(lambda_trash.first_name).to eq 'Michael'.reverse
129
- end
130
-
131
- it 'does not translate the value given as right property' do
132
- lambda_trash.first_name = 'Michael'
133
- expect(lambda_trash.first_name).to eq 'Michael'
134
- end
135
- end
136
-
137
- describe 'translating multiple properties using a proc' do
138
- class SomeDataModel < Hashie::Trash
139
- property :value_a, from: :config, with: ->(config) { config.a }
140
- property :value_b, from: :config, with: ->(config) { config.b }
141
- end
142
-
143
- ConfigDataModel = Struct.new(:a, :b)
144
-
145
- subject { SomeDataModel.new(config: ConfigDataModel.new('value in a', 'value in b')) }
146
-
147
- it 'translates the first key' do
148
- expect(subject.value_a).to eq 'value in a'
149
- end
150
-
151
- it 'translates the second key' do
152
- expect(subject.value_b).to eq 'value in b'
153
- end
154
-
155
- it 'maintains translations hash mapping from the original to the translated name' do
156
- expect(SomeDataModel.translations).to eq(config: %i[value_a value_b])
157
- end
158
- end
159
-
160
- describe 'uses with or transform_with interchangeably' do
161
- class TrashLambdaTestTransformWith < Hashie::Trash
162
- property :first_name, from: :firstName, transform_with: ->(value) { value.reverse }
163
- end
164
-
165
- let(:lambda_trash) { TrashLambdaTestTransformWith.new }
166
-
167
- it 'translates the value given as property with the given lambda' do
168
- lambda_trash.firstName = 'Michael'
169
- expect(lambda_trash.first_name).to eq 'Michael'.reverse
170
- end
171
-
172
- it 'does not translate the value given as right property' do
173
- lambda_trash.first_name = 'Michael'
174
- expect(lambda_trash.first_name).to eq 'Michael'
175
- end
176
- end
177
-
178
- describe 'translating properties without from option using a proc' do
179
- class TrashLambdaTestWithProperties < Hashie::Trash
180
- property :first_name, transform_with: ->(value) { value.reverse }
181
- end
182
-
183
- let(:lambda_trash) { TrashLambdaTestWithProperties.new }
184
-
185
- it 'translates the value given as property with the given lambda' do
186
- lambda_trash.first_name = 'Michael'
187
- expect(lambda_trash.first_name).to eq 'Michael'.reverse
188
- end
189
-
190
- it 'transforms the value when given in constructor' do
191
- expect(TrashLambdaTestWithProperties.new(first_name: 'Michael').first_name).to eq 'Michael'.reverse
192
- end
193
-
194
- context 'when :from option is given' do
195
- class TrashLambdaTest3 < Hashie::Trash
196
- property :first_name, from: :firstName, transform_with: ->(value) { value.reverse }
197
- end
198
-
199
- it 'does not override the :from option in the constructor' do
200
- expect(TrashLambdaTest3.new(first_name: 'Michael').first_name).to eq 'Michael'
201
- end
202
-
203
- it 'does not override the :from option when given as property' do
204
- t = TrashLambdaTest3.new
205
- t.first_name = 'Michael'
206
- expect(t.first_name).to eq 'Michael'
207
- end
208
- end
209
- end
210
-
211
- describe 'inheritable transforms' do
212
- class TransformA < Hashie::Trash
213
- property :some_value, transform_with: ->(v) { v.to_i }
214
- end
215
-
216
- class TransformB < TransformA
217
- property :some_other_value, transform_with: ->(v) { v.to_i }
218
- end
219
-
220
- class TransformC < TransformB
221
- property :some_value, transform_with: ->(v) { -v.to_i }
222
- end
223
-
224
- it 'inherit properties transforms' do
225
- expect(TransformB.new(some_value: '123', some_other_value: '456').some_value).to eq(123)
226
- end
227
-
228
- it 'replaces property transform' do
229
- expect(TransformC.new(some_value: '123', some_other_value: '456').some_value).to eq(-123)
230
- end
231
- end
232
-
233
- describe 'inheritable translations' do
234
- class TranslationA < Hashie::Trash
235
- property :some_value, from: 'someValue', with: ->(v) { v.to_i }
236
- end
237
-
238
- class TranslationB < TranslationA
239
- property :some_other_value, from: 'someOtherValue'
240
- end
241
-
242
- it 'inherit properties translations' do
243
- expect(TranslationB.new('someValue' => '123').some_value).to eq(123)
244
- end
245
- end
246
-
247
- it 'raises an error when :from have the same value as property' do
248
- expect do
249
- class WrongTrash < Hashie::Trash
250
- property :first_name, from: :first_name
251
- end
252
- end.to raise_error(ArgumentError)
253
- end
254
-
255
- context 'when subclassing' do
256
- class Person < Hashie::Trash
257
- property :first_name, from: :firstName
258
- end
259
-
260
- class Hobbit < Person; end
261
-
262
- subject { Hobbit.new(firstName: 'Frodo') }
263
-
264
- it 'keeps translation definitions in subclasses' do
265
- expect(subject.first_name).to eq('Frodo')
266
- end
267
- end
268
-
269
- context 'when copying properties from other properties' do
270
- it 'retains the original and also sets the copy' do
271
- simple = Class.new(Hashie::Trash) do
272
- property :id
273
- property :copy_of_id, from: :id
274
- end
275
-
276
- subject = simple.new(id: 1)
277
-
278
- expect(subject.id).to eq(1)
279
- expect(subject.copy_of_id).to eq(1)
280
- end
281
-
282
- it 'grabs the default for the original if it is not set' do
283
- with_default = Class.new(Hashie::Trash) do
284
- property :id, default: 0
285
- property :copy_of_id, from: :id
286
- end
287
-
288
- subject = with_default.new
289
-
290
- expect(subject.id).to eq(0)
291
- expect(subject.copy_of_id).to eq(0)
292
- end
293
-
294
- it 'can be a required value' do
295
- with_required = Class.new(Hashie::Trash) do
296
- property :id
297
- property :copy_of_id, from: :id, required: true, message: 'must be set'
298
- end
299
-
300
- expect { with_required.new }.to raise_error(ArgumentError, "The property 'copy_of_id' must be set")
301
- end
302
-
303
- it 'does not set properties that do not exist' do
304
- from_non_property = Class.new(Hashie::Trash) do
305
- property :copy_of_value, from: :value
306
- end
307
-
308
- subject = from_non_property.new(value: 0)
309
-
310
- expect(subject).not_to respond_to(:value)
311
- expect { subject[:value] }.to raise_error(NoMethodError, "The property 'value' is not defined for .")
312
- expect(subject.to_h[:value]).to eq(nil)
313
- expect(subject.copy_of_value).to eq(0)
314
- end
315
-
316
- it 'is not order-dependent in definition' do
317
- simple = Class.new(Hashie::Trash) do
318
- property :copy_of_id, from: :id
319
- property :id
320
- end
321
-
322
- subject = simple.new(id: 1)
323
-
324
- expect(subject.id).to eq(1)
325
- expect(subject.copy_of_id).to eq(1)
326
- end
327
- end
328
- end