hashie 3.5.7 → 4.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +240 -164
  3. data/CONTRIBUTING.md +13 -6
  4. data/README.md +210 -29
  5. data/Rakefile +2 -2
  6. data/UPGRADING.md +83 -7
  7. data/hashie.gemspec +13 -7
  8. data/lib/hashie.rb +21 -19
  9. data/lib/hashie/clash.rb +12 -1
  10. data/lib/hashie/dash.rb +42 -21
  11. data/lib/hashie/extensions/active_support/core_ext/hash.rb +14 -0
  12. data/lib/hashie/extensions/coercion.rb +26 -19
  13. data/lib/hashie/extensions/dash/indifferent_access.rb +20 -1
  14. data/lib/hashie/extensions/dash/property_translation.rb +54 -28
  15. data/lib/hashie/extensions/deep_fetch.rb +5 -3
  16. data/lib/hashie/extensions/deep_find.rb +14 -5
  17. data/lib/hashie/extensions/deep_locate.rb +22 -8
  18. data/lib/hashie/extensions/deep_merge.rb +26 -10
  19. data/lib/hashie/extensions/indifferent_access.rb +8 -8
  20. data/lib/hashie/extensions/key_conflict_warning.rb +55 -0
  21. data/lib/hashie/extensions/mash/define_accessors.rb +90 -0
  22. data/lib/hashie/extensions/mash/keep_original_keys.rb +4 -5
  23. data/lib/hashie/extensions/mash/permissive_respond_to.rb +61 -0
  24. data/lib/hashie/extensions/mash/safe_assignment.rb +3 -1
  25. data/lib/hashie/extensions/mash/symbolize_keys.rb +1 -1
  26. data/lib/hashie/extensions/method_access.rb +47 -14
  27. data/lib/hashie/extensions/parsers/yaml_erb_parser.rb +28 -4
  28. data/lib/hashie/extensions/ruby_version_check.rb +5 -1
  29. data/lib/hashie/extensions/strict_key_access.rb +16 -13
  30. data/lib/hashie/extensions/stringify_keys.rb +1 -1
  31. data/lib/hashie/extensions/symbolize_keys.rb +1 -1
  32. data/lib/hashie/hash.rb +18 -11
  33. data/lib/hashie/mash.rb +131 -70
  34. data/lib/hashie/railtie.rb +7 -0
  35. data/lib/hashie/rash.rb +6 -6
  36. data/lib/hashie/utils.rb +28 -0
  37. data/lib/hashie/version.rb +1 -1
  38. metadata +19 -128
  39. data/spec/hashie/array_spec.rb +0 -29
  40. data/spec/hashie/clash_spec.rb +0 -70
  41. data/spec/hashie/dash_spec.rb +0 -573
  42. data/spec/hashie/extensions/autoload_spec.rb +0 -24
  43. data/spec/hashie/extensions/coercion_spec.rb +0 -631
  44. data/spec/hashie/extensions/dash/coercion_spec.rb +0 -13
  45. data/spec/hashie/extensions/dash/indifferent_access_spec.rb +0 -84
  46. data/spec/hashie/extensions/deep_fetch_spec.rb +0 -97
  47. data/spec/hashie/extensions/deep_find_spec.rb +0 -138
  48. data/spec/hashie/extensions/deep_locate_spec.rb +0 -137
  49. data/spec/hashie/extensions/deep_merge_spec.rb +0 -70
  50. data/spec/hashie/extensions/ignore_undeclared_spec.rb +0 -47
  51. data/spec/hashie/extensions/indifferent_access_spec.rb +0 -282
  52. data/spec/hashie/extensions/indifferent_access_with_rails_hwia_spec.rb +0 -208
  53. data/spec/hashie/extensions/key_conversion_spec.rb +0 -12
  54. data/spec/hashie/extensions/mash/keep_original_keys_spec.rb +0 -46
  55. data/spec/hashie/extensions/mash/safe_assignment_spec.rb +0 -50
  56. data/spec/hashie/extensions/mash/symbolize_keys_spec.rb +0 -39
  57. data/spec/hashie/extensions/merge_initializer_spec.rb +0 -23
  58. data/spec/hashie/extensions/method_access_spec.rb +0 -188
  59. data/spec/hashie/extensions/strict_key_access_spec.rb +0 -110
  60. data/spec/hashie/extensions/stringify_keys_spec.rb +0 -124
  61. data/spec/hashie/extensions/symbolize_keys_spec.rb +0 -129
  62. data/spec/hashie/hash_spec.rb +0 -84
  63. data/spec/hashie/mash_spec.rb +0 -763
  64. data/spec/hashie/parsers/yaml_erb_parser_spec.rb +0 -46
  65. data/spec/hashie/rash_spec.rb +0 -83
  66. data/spec/hashie/trash_spec.rb +0 -268
  67. data/spec/hashie/utils_spec.rb +0 -25
  68. data/spec/hashie/version_spec.rb +0 -7
  69. data/spec/hashie_spec.rb +0 -13
  70. data/spec/integration/omniauth-oauth2/app.rb +0 -53
  71. data/spec/integration/omniauth-oauth2/integration_spec.rb +0 -26
  72. data/spec/integration/omniauth-oauth2/some_site.rb +0 -38
  73. data/spec/integration/omniauth/app.rb +0 -11
  74. data/spec/integration/omniauth/integration_spec.rb +0 -38
  75. data/spec/integration/rails-without-dependency/integration_spec.rb +0 -15
  76. data/spec/integration/rails/app.rb +0 -48
  77. data/spec/integration/rails/integration_spec.rb +0 -26
  78. data/spec/spec_helper.rb +0 -23
  79. data/spec/support/integration_specs.rb +0 -36
  80. data/spec/support/logger.rb +0 -24
  81. data/spec/support/module_context.rb +0 -11
  82. 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
- <<-EOF
8
- ---
9
- foo: verbatim
10
- bar: <%= "erb" %>
11
- baz: "<%= __FILE__ %>"
12
- EOF
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,268 +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: [: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
- end
@@ -1,25 +0,0 @@
1
- require 'spec_helper'
2
-
3
- def a_method_to_match_against
4
- 'Hello world!'
5
- end
6
-
7
- RSpec.describe Hashie::Utils do
8
- describe '.method_information' do
9
- it 'states the module or class that a native method was defined in' do
10
- bound_method = method(:trust)
11
-
12
- message = Hashie::Utils.method_information(bound_method)
13
-
14
- expect(message).to match('Kernel')
15
- end
16
-
17
- it 'states the line a Ruby method was defined at' do
18
- bound_method = method(:a_method_to_match_against)
19
-
20
- message = Hashie::Utils.method_information(bound_method)
21
-
22
- expect(message).to match('spec/hashie/utils_spec.rb')
23
- end
24
- end
25
- end
@@ -1,7 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Hashie do
4
- it 'has a version' do
5
- expect(Hashie::VERSION).not_to be_nil
6
- end
7
- end
data/spec/hashie_spec.rb DELETED
@@ -1,13 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe Hashie do
4
- describe '.logger' do
5
- include_context 'with a logger'
6
-
7
- it 'is available via an accessor' do
8
- Hashie.logger.info('Fee fi fo fum')
9
-
10
- expect(logger_output).to match('Fee fi fo fum')
11
- end
12
- end
13
- end