hashie 4.0.0 → 4.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +213 -187
  3. data/CONTRIBUTING.md +13 -6
  4. data/README.md +33 -9
  5. data/UPGRADING.md +5 -5
  6. data/hashie.gemspec +11 -6
  7. data/lib/hashie.rb +1 -0
  8. data/lib/hashie/extensions/dash/property_translation.rb +1 -1
  9. data/lib/hashie/extensions/deep_merge.rb +18 -1
  10. data/lib/hashie/extensions/mash/permissive_respond_to.rb +61 -0
  11. data/lib/hashie/extensions/parsers/yaml_erb_parser.rb +19 -2
  12. data/lib/hashie/extensions/ruby_version_check.rb +5 -1
  13. data/lib/hashie/mash.rb +31 -26
  14. data/lib/hashie/utils.rb +28 -0
  15. data/lib/hashie/version.rb +1 -1
  16. metadata +16 -131
  17. data/spec/hashie/array_spec.rb +0 -29
  18. data/spec/hashie/clash_spec.rb +0 -70
  19. data/spec/hashie/dash_spec.rb +0 -608
  20. data/spec/hashie/extensions/autoload_spec.rb +0 -24
  21. data/spec/hashie/extensions/coercion_spec.rb +0 -648
  22. data/spec/hashie/extensions/dash/coercion_spec.rb +0 -13
  23. data/spec/hashie/extensions/dash/indifferent_access_spec.rb +0 -84
  24. data/spec/hashie/extensions/deep_fetch_spec.rb +0 -97
  25. data/spec/hashie/extensions/deep_find_spec.rb +0 -144
  26. data/spec/hashie/extensions/deep_locate_spec.rb +0 -138
  27. data/spec/hashie/extensions/deep_merge_spec.rb +0 -74
  28. data/spec/hashie/extensions/ignore_undeclared_spec.rb +0 -48
  29. data/spec/hashie/extensions/indifferent_access_spec.rb +0 -295
  30. data/spec/hashie/extensions/indifferent_access_with_rails_hwia_spec.rb +0 -208
  31. data/spec/hashie/extensions/key_conversion_spec.rb +0 -12
  32. data/spec/hashie/extensions/mash/define_accessors_spec.rb +0 -90
  33. data/spec/hashie/extensions/mash/keep_original_keys_spec.rb +0 -46
  34. data/spec/hashie/extensions/mash/safe_assignment_spec.rb +0 -50
  35. data/spec/hashie/extensions/mash/symbolize_keys_spec.rb +0 -39
  36. data/spec/hashie/extensions/merge_initializer_spec.rb +0 -23
  37. data/spec/hashie/extensions/method_access_spec.rb +0 -233
  38. data/spec/hashie/extensions/strict_key_access_spec.rb +0 -109
  39. data/spec/hashie/extensions/stringify_keys_spec.rb +0 -124
  40. data/spec/hashie/extensions/symbolize_keys_spec.rb +0 -131
  41. data/spec/hashie/hash_spec.rb +0 -123
  42. data/spec/hashie/mash_spec.rb +0 -1077
  43. data/spec/hashie/parsers/yaml_erb_parser_spec.rb +0 -46
  44. data/spec/hashie/rash_spec.rb +0 -83
  45. data/spec/hashie/trash_spec.rb +0 -334
  46. data/spec/hashie/utils_spec.rb +0 -25
  47. data/spec/hashie/version_spec.rb +0 -7
  48. data/spec/hashie_spec.rb +0 -13
  49. data/spec/integration/elasticsearch/integration_spec.rb +0 -41
  50. data/spec/integration/omniauth-oauth2/app.rb +0 -52
  51. data/spec/integration/omniauth-oauth2/integration_spec.rb +0 -26
  52. data/spec/integration/omniauth-oauth2/some_site.rb +0 -38
  53. data/spec/integration/omniauth/app.rb +0 -11
  54. data/spec/integration/omniauth/integration_spec.rb +0 -38
  55. data/spec/integration/rails-without-dependency/integration_spec.rb +0 -15
  56. data/spec/integration/rails/app.rb +0 -40
  57. data/spec/integration/rails/integration_spec.rb +0 -47
  58. data/spec/spec_helper.rb +0 -23
  59. data/spec/support/integration_specs.rb +0 -36
  60. data/spec/support/logger.rb +0 -24
  61. data/spec/support/module_context.rb +0 -11
  62. 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,334 +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(
192
- TrashLambdaTestWithProperties.new(first_name: 'Michael').first_name
193
- ).to eq 'Michael'.reverse
194
- end
195
-
196
- context 'when :from option is given' do
197
- class TrashLambdaTest3 < Hashie::Trash
198
- property :first_name, from: :firstName, transform_with: ->(value) { value.reverse }
199
- end
200
-
201
- it 'does not override the :from option in the constructor' do
202
- expect(TrashLambdaTest3.new(first_name: 'Michael').first_name).to eq 'Michael'
203
- end
204
-
205
- it 'does not override the :from option when given as property' do
206
- t = TrashLambdaTest3.new
207
- t.first_name = 'Michael'
208
- expect(t.first_name).to eq 'Michael'
209
- end
210
- end
211
- end
212
-
213
- describe 'inheritable transforms' do
214
- class TransformA < Hashie::Trash
215
- property :some_value, transform_with: ->(v) { v.to_i }
216
- end
217
-
218
- class TransformB < TransformA
219
- property :some_other_value, transform_with: ->(v) { v.to_i }
220
- end
221
-
222
- class TransformC < TransformB
223
- property :some_value, transform_with: ->(v) { -v.to_i }
224
- end
225
-
226
- it 'inherit properties transforms' do
227
- expect(TransformB.new(some_value: '123', some_other_value: '456').some_value).to eq(123)
228
- end
229
-
230
- it 'replaces property transform' do
231
- expect(TransformC.new(some_value: '123', some_other_value: '456').some_value).to eq(-123)
232
- end
233
- end
234
-
235
- describe 'inheritable translations' do
236
- class TranslationA < Hashie::Trash
237
- property :some_value, from: 'someValue', with: ->(v) { v.to_i }
238
- end
239
-
240
- class TranslationB < TranslationA
241
- property :some_other_value, from: 'someOtherValue'
242
- end
243
-
244
- it 'inherit properties translations' do
245
- expect(TranslationB.new('someValue' => '123').some_value).to eq(123)
246
- end
247
- end
248
-
249
- it 'raises an error when :from have the same value as property' do
250
- expect do
251
- class WrongTrash < Hashie::Trash
252
- property :first_name, from: :first_name
253
- end
254
- end.to raise_error(ArgumentError)
255
- end
256
-
257
- context 'when subclassing' do
258
- class Person < Hashie::Trash
259
- property :first_name, from: :firstName
260
- end
261
-
262
- class Hobbit < Person; end
263
-
264
- subject { Hobbit.new(firstName: 'Frodo') }
265
-
266
- it 'keeps translation definitions in subclasses' do
267
- expect(subject.first_name).to eq('Frodo')
268
- end
269
- end
270
-
271
- context 'when copying properties from other properties' do
272
- it 'retains the original and also sets the copy' do
273
- simple = Class.new(Hashie::Trash) do
274
- property :id
275
- property :copy_of_id, from: :id
276
- end
277
-
278
- subject = simple.new(id: 1)
279
-
280
- expect(subject.id).to eq(1)
281
- expect(subject.copy_of_id).to eq(1)
282
- end
283
-
284
- it 'grabs the default for the original if it is not set' do
285
- with_default = Class.new(Hashie::Trash) do
286
- property :id, default: 0
287
- property :copy_of_id, from: :id
288
- end
289
-
290
- subject = with_default.new
291
-
292
- expect(subject.id).to eq(0)
293
- expect(subject.copy_of_id).to eq(0)
294
- end
295
-
296
- it 'can be a required value' do
297
- with_required = Class.new(Hashie::Trash) do
298
- property :id
299
- property :copy_of_id, from: :id, required: true, message: 'must be set'
300
- end
301
-
302
- expect { with_required.new }.to raise_error(
303
- ArgumentError, "The property 'copy_of_id' must be set"
304
- )
305
- end
306
-
307
- it 'does not set properties that do not exist' do
308
- from_non_property = Class.new(Hashie::Trash) do
309
- property :copy_of_value, from: :value
310
- end
311
-
312
- subject = from_non_property.new(value: 0)
313
-
314
- expect(subject).not_to respond_to(:value)
315
- expect { subject[:value] }.to raise_error(
316
- NoMethodError, "The property 'value' is not defined for ."
317
- )
318
- expect(subject.to_h[:value]).to eq(nil)
319
- expect(subject.copy_of_value).to eq(0)
320
- end
321
-
322
- it 'is not order-dependent in definition' do
323
- simple = Class.new(Hashie::Trash) do
324
- property :copy_of_id, from: :id
325
- property :id
326
- end
327
-
328
- subject = simple.new(id: 1)
329
-
330
- expect(subject.id).to eq(1)
331
- expect(subject.copy_of_id).to eq(1)
332
- end
333
- end
334
- end