hashie 3.5.7 → 3.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.md +22 -0
- data/README.md +91 -22
- data/Rakefile +2 -2
- data/hashie.gemspec +1 -1
- data/lib/hashie/clash.rb +12 -1
- data/lib/hashie/dash.rb +41 -21
- data/lib/hashie/extensions/coercion.rb +5 -5
- data/lib/hashie/extensions/dash/property_translation.rb +49 -26
- data/lib/hashie/extensions/deep_fetch.rb +1 -1
- data/lib/hashie/extensions/deep_find.rb +2 -2
- data/lib/hashie/extensions/deep_locate.rb +4 -5
- data/lib/hashie/extensions/deep_merge.rb +8 -9
- data/lib/hashie/extensions/indifferent_access.rb +7 -5
- data/lib/hashie/extensions/mash/keep_original_keys.rb +3 -5
- data/lib/hashie/extensions/mash/safe_assignment.rb +1 -1
- data/lib/hashie/extensions/mash/symbolize_keys.rb +1 -1
- data/lib/hashie/extensions/method_access.rb +47 -17
- data/lib/hashie/extensions/parsers/yaml_erb_parser.rb +3 -1
- data/lib/hashie/extensions/strict_key_access.rb +8 -9
- data/lib/hashie/extensions/stringify_keys.rb +1 -1
- data/lib/hashie/extensions/symbolize_keys.rb +1 -1
- data/lib/hashie/hash.rb +4 -4
- data/lib/hashie/mash.rb +22 -22
- data/lib/hashie/rash.rb +5 -5
- data/lib/hashie/version.rb +1 -1
- data/spec/hashie/array_spec.rb +1 -1
- data/spec/hashie/dash_spec.rb +27 -2
- data/spec/hashie/extensions/coercion_spec.rb +20 -12
- data/spec/hashie/extensions/deep_locate_spec.rb +1 -1
- data/spec/hashie/extensions/deep_merge_spec.rb +1 -1
- data/spec/hashie/extensions/indifferent_access_spec.rb +20 -7
- data/spec/hashie/extensions/indifferent_access_with_rails_hwia_spec.rb +5 -5
- data/spec/hashie/extensions/method_access_spec.rb +42 -4
- data/spec/hashie/extensions/stringify_keys_spec.rb +4 -4
- data/spec/hashie/extensions/symbolize_keys_spec.rb +3 -3
- data/spec/hashie/mash_spec.rb +16 -8
- data/spec/hashie/parsers/yaml_erb_parser_spec.rb +3 -3
- data/spec/hashie/rash_spec.rb +2 -2
- data/spec/hashie/trash_spec.rb +61 -1
- data/spec/integration/elasticsearch/integration_spec.rb +40 -0
- data/spec/integration/omniauth-oauth2/app.rb +3 -4
- data/spec/integration/omniauth-oauth2/some_site.rb +2 -2
- data/spec/integration/rails/app.rb +3 -4
- metadata +5 -3
data/lib/hashie/rash.rb
CHANGED
@@ -64,7 +64,7 @@ module Hashie
|
|
64
64
|
# Raise (or yield) unless something matches the key.
|
65
65
|
#
|
66
66
|
def fetch(*args)
|
67
|
-
|
67
|
+
raise ArgumentError, "Expected 1-2 arguments, got #{args.length}" \
|
68
68
|
unless (1..2).cover?(args.length)
|
69
69
|
|
70
70
|
key, default = args
|
@@ -78,7 +78,7 @@ module Hashie
|
|
78
78
|
elsif default
|
79
79
|
default
|
80
80
|
else
|
81
|
-
|
81
|
+
raise KeyError, "key not found: #{key.inspect}"
|
82
82
|
end
|
83
83
|
end
|
84
84
|
|
@@ -125,11 +125,11 @@ module Hashie
|
|
125
125
|
end
|
126
126
|
|
127
127
|
def method_missing(*args, &block)
|
128
|
-
@hash.send(*args, &block)
|
128
|
+
@hash.send(*args, &block) || super
|
129
129
|
end
|
130
130
|
|
131
|
-
def respond_to_missing?(
|
132
|
-
@hash.respond_to?(
|
131
|
+
def respond_to_missing?(method_name, _include_private = false)
|
132
|
+
@hash.respond_to?(method_name)
|
133
133
|
end
|
134
134
|
|
135
135
|
private
|
data/lib/hashie/version.rb
CHANGED
data/spec/hashie/array_spec.rb
CHANGED
data/spec/hashie/dash_spec.rb
CHANGED
@@ -310,7 +310,7 @@ describe DashTest do
|
|
310
310
|
|
311
311
|
describe 'properties' do
|
312
312
|
it 'lists defined properties' do
|
313
|
-
expect(described_class.properties).to eq Set.new([
|
313
|
+
expect(described_class.properties).to eq Set.new(%i[first_name email count])
|
314
314
|
end
|
315
315
|
|
316
316
|
it 'checks if a property exists' do
|
@@ -348,7 +348,7 @@ describe DashTest do
|
|
348
348
|
end
|
349
349
|
|
350
350
|
it 'leaves only specified keys and keys with default values' do
|
351
|
-
expect(subject.keys.sort_by(&:to_s)).to eq [
|
351
|
+
expect(subject.keys.sort_by(&:to_s)).to eq %i[count first_name]
|
352
352
|
expect(subject.email).to be_nil
|
353
353
|
expect(subject.count).to eq 0
|
354
354
|
end
|
@@ -402,6 +402,31 @@ describe DashTest do
|
|
402
402
|
expect(subject.count).to eq subject.class.defaults[:count]
|
403
403
|
end
|
404
404
|
end
|
405
|
+
|
406
|
+
context 'codependent attributes' do
|
407
|
+
let(:codependent) do
|
408
|
+
Class.new(Hashie::Dash) do
|
409
|
+
property :a, required: -> { b.nil? }, message: 'is required if b is not set.'
|
410
|
+
property :b, required: -> { a.nil? }, message: 'is required if a is not set.'
|
411
|
+
end
|
412
|
+
end
|
413
|
+
|
414
|
+
it 'does not raise an error when only the first property is set' do
|
415
|
+
expect { codependent.new(a: 'ant', b: nil) }.not_to raise_error
|
416
|
+
end
|
417
|
+
|
418
|
+
it 'does not raise an error when only the second property is set' do
|
419
|
+
expect { codependent.new(a: nil, b: 'bat') }.not_to raise_error
|
420
|
+
end
|
421
|
+
|
422
|
+
it 'does not raise an error when both properties are set' do
|
423
|
+
expect { codependent.new(a: 'ant', b: 'bat') }.not_to raise_error
|
424
|
+
end
|
425
|
+
|
426
|
+
it 'raises an error when neither property is set' do
|
427
|
+
expect { codependent.new(a: nil, b: nil) }.to raise_error(ArgumentError)
|
428
|
+
end
|
429
|
+
end
|
405
430
|
end
|
406
431
|
end
|
407
432
|
|
@@ -154,7 +154,7 @@ describe Hashie::Extensions::Coercion do
|
|
154
154
|
it 'supports coercion for Array' do
|
155
155
|
subject.coerce_key :foo, Array[Coercable]
|
156
156
|
|
157
|
-
instance[:foo] = %w
|
157
|
+
instance[:foo] = %w[bar bar2]
|
158
158
|
expect(instance[:foo]).to all(be_coerced)
|
159
159
|
expect(instance[:foo]).to be_a(Array)
|
160
160
|
end
|
@@ -162,7 +162,7 @@ describe Hashie::Extensions::Coercion do
|
|
162
162
|
it 'supports coercion for Set' do
|
163
163
|
subject.coerce_key :foo, Set[Coercable]
|
164
164
|
|
165
|
-
instance[:foo] = Set.new(%w
|
165
|
+
instance[:foo] = Set.new(%w[bar bar2])
|
166
166
|
expect(instance[:foo]).to all(be_coerced)
|
167
167
|
expect(instance[:foo]).to be_a(Set)
|
168
168
|
end
|
@@ -170,7 +170,7 @@ describe Hashie::Extensions::Coercion do
|
|
170
170
|
it 'supports coercion for Set of primitive' do
|
171
171
|
subject.coerce_key :foo, Set[Initializable]
|
172
172
|
|
173
|
-
instance[:foo] = %w
|
173
|
+
instance[:foo] = %w[bar bar2]
|
174
174
|
expect(instance[:foo].map(&:value)).to all(eq 'String')
|
175
175
|
expect(instance[:foo]).to be_none(&:coerced?)
|
176
176
|
expect(instance[:foo]).to be_a(Set)
|
@@ -558,18 +558,26 @@ describe Hashie::Extensions::Coercion do
|
|
558
558
|
end
|
559
559
|
|
560
560
|
it 'raises a CoercionError when coercion is not possible' do
|
561
|
-
type =
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
561
|
+
type =
|
562
|
+
if Hashie::Extensions::RubyVersion.new(RUBY_VERSION) >= Hashie::Extensions::RubyVersion.new('2.4.0')
|
563
|
+
Integer
|
564
|
+
else
|
565
|
+
Fixnum # rubocop:disable Lint/UnifiedInteger
|
566
|
+
end
|
566
567
|
|
567
568
|
subject.coerce_value type, Symbol
|
568
569
|
expect { instance[:hi] = 1 }.to raise_error(Hashie::CoercionError, /Cannot coerce property :hi from #{type} to Symbol/)
|
569
570
|
end
|
570
571
|
|
571
572
|
it 'coerces Integer to String' do
|
572
|
-
|
573
|
+
type =
|
574
|
+
if Hashie::Extensions::RubyVersion.new(RUBY_VERSION) >= Hashie::Extensions::RubyVersion.new('2.4.0')
|
575
|
+
Integer
|
576
|
+
else
|
577
|
+
Fixnum # rubocop:disable Lint/UnifiedInteger
|
578
|
+
end
|
579
|
+
|
580
|
+
subject.coerce_value type, String
|
573
581
|
|
574
582
|
{
|
575
583
|
fixnum: 2,
|
@@ -579,7 +587,7 @@ describe Hashie::Extensions::Coercion do
|
|
579
587
|
complex: Complex(1)
|
580
588
|
}.each do |k, v|
|
581
589
|
instance[k] = v
|
582
|
-
if v.is_a?
|
590
|
+
if v.is_a? type
|
583
591
|
expect(instance[k]).to be_a(String)
|
584
592
|
expect(instance[k]).to eq(v.to_s)
|
585
593
|
else
|
@@ -610,8 +618,8 @@ describe Hashie::Extensions::Coercion do
|
|
610
618
|
return !!(v =~ /^(true|t|yes|y|1)$/i)
|
611
619
|
end)
|
612
620
|
|
613
|
-
true_values = %w
|
614
|
-
false_values = %w
|
621
|
+
true_values = %w[true t yes y 1]
|
622
|
+
false_values = %w[false f no n 0]
|
615
623
|
|
616
624
|
true_values.each do |v|
|
617
625
|
instance[:foo] = v
|
@@ -78,7 +78,7 @@ describe Hashie::Extensions::DeepLocate do
|
|
78
78
|
[
|
79
79
|
lambda do |_key, _value, object|
|
80
80
|
object.is_a?(Array) &&
|
81
|
-
|
81
|
+
!object.extend(described_class).deep_locate(:match).empty?
|
82
82
|
end,
|
83
83
|
[
|
84
84
|
hash[:query][:bool][:must],
|
@@ -28,7 +28,7 @@ describe Hashie::Extensions::DeepMerge do
|
|
28
28
|
|
29
29
|
it 'merges new nested hash entries by value, not by reference' do
|
30
30
|
h1.deep_merge!(h2)
|
31
|
-
expect { h1[:e][:e1] = 'changed' }.not_to
|
31
|
+
expect { h1[:e][:e1] = 'changed' }.not_to(change { h2[:e][:e1] })
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
@@ -6,7 +6,7 @@ describe Hashie::Extensions::IndifferentAccess do
|
|
6
6
|
include Hashie::Extensions::IndifferentAccess
|
7
7
|
|
8
8
|
class << self
|
9
|
-
|
9
|
+
alias build new
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
@@ -14,7 +14,7 @@ describe Hashie::Extensions::IndifferentAccess do
|
|
14
14
|
include Hashie::Extensions::IndifferentAccess
|
15
15
|
|
16
16
|
class << self
|
17
|
-
|
17
|
+
alias build []
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
@@ -22,7 +22,7 @@ describe Hashie::Extensions::IndifferentAccess do
|
|
22
22
|
include Hashie::Extensions::IndifferentAccess
|
23
23
|
|
24
24
|
class << self
|
25
|
-
|
25
|
+
alias build try_convert
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
@@ -44,11 +44,24 @@ describe Hashie::Extensions::IndifferentAccess do
|
|
44
44
|
include Hashie::Extensions::IndifferentAccess
|
45
45
|
end.new
|
46
46
|
|
47
|
-
merged_hash = indifferent_hash.merge(:
|
47
|
+
merged_hash = indifferent_hash.merge(cat: 'meow')
|
48
48
|
|
49
49
|
expect(merged_hash[:cat]).to eq('meow')
|
50
50
|
expect(merged_hash['cat']).to eq('meow')
|
51
51
|
end
|
52
|
+
|
53
|
+
it 'injects the resulting new Hash with IndifferentAccess' do
|
54
|
+
hash = IndifferentHashWithMergeInitializer.new(
|
55
|
+
:cat => 'meow',
|
56
|
+
'dog' => { name: 'Mango', sound: 'woof' }
|
57
|
+
)
|
58
|
+
|
59
|
+
dog = hash[:dog]
|
60
|
+
merged = dog.merge(foo: 'bar')
|
61
|
+
|
62
|
+
expect(merged[:foo]).to eq('bar')
|
63
|
+
expect(merged['foo']).to eq('bar')
|
64
|
+
end
|
52
65
|
end
|
53
66
|
|
54
67
|
describe '#merge!' do
|
@@ -57,7 +70,7 @@ describe Hashie::Extensions::IndifferentAccess do
|
|
57
70
|
include Hashie::Extensions::IndifferentAccess
|
58
71
|
end.new
|
59
72
|
|
60
|
-
indifferent_hash
|
73
|
+
indifferent_hash[:cat] = 'meow'
|
61
74
|
|
62
75
|
expect(indifferent_hash[:cat]).to eq('meow')
|
63
76
|
expect(indifferent_hash['cat']).to eq('meow')
|
@@ -113,7 +126,7 @@ describe Hashie::Extensions::IndifferentAccess do
|
|
113
126
|
describe '#values_at' do
|
114
127
|
it 'indifferently finds values' do
|
115
128
|
h = subject.build(:foo => 'bar', 'baz' => 'qux')
|
116
|
-
expect(h.values_at('foo', :baz)).to eq %w
|
129
|
+
expect(h.values_at('foo', :baz)).to eq %w[bar qux]
|
117
130
|
end
|
118
131
|
|
119
132
|
it 'returns the same instance of the hash that was set' do
|
@@ -195,7 +208,7 @@ describe Hashie::Extensions::IndifferentAccess do
|
|
195
208
|
expect(h).to be_key('foo')
|
196
209
|
end
|
197
210
|
|
198
|
-
%w
|
211
|
+
%w[include? member? has_key?].each do |key_alias|
|
199
212
|
it "is aliased as #{key_alias}" do
|
200
213
|
expect(h.send(key_alias.to_sym, :foo)).to be(true)
|
201
214
|
expect(h.send(key_alias.to_sym, 'foo')).to be(true)
|
@@ -11,7 +11,7 @@ describe Hashie::Extensions::IndifferentAccess do
|
|
11
11
|
include Hashie::Extensions::IndifferentAccess
|
12
12
|
|
13
13
|
class << self
|
14
|
-
|
14
|
+
alias build new
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
@@ -19,7 +19,7 @@ describe Hashie::Extensions::IndifferentAccess do
|
|
19
19
|
include Hashie::Extensions::IndifferentAccess
|
20
20
|
|
21
21
|
class << self
|
22
|
-
|
22
|
+
alias build []
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
@@ -27,7 +27,7 @@ describe Hashie::Extensions::IndifferentAccess do
|
|
27
27
|
include Hashie::Extensions::IndifferentAccess
|
28
28
|
|
29
29
|
class << self
|
30
|
-
|
30
|
+
alias build try_convert
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
@@ -54,7 +54,7 @@ describe Hashie::Extensions::IndifferentAccess do
|
|
54
54
|
:foo => 'bar', 'baz' => 'qux'
|
55
55
|
)
|
56
56
|
h = subject.build(indifferent_hash)
|
57
|
-
expect(h.values_at('foo', :baz)).to eq %w
|
57
|
+
expect(h.values_at('foo', :baz)).to eq %w[bar qux]
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
@@ -91,7 +91,7 @@ describe Hashie::Extensions::IndifferentAccess do
|
|
91
91
|
expect(h).to be_key('foo')
|
92
92
|
end
|
93
93
|
|
94
|
-
%w
|
94
|
+
%w[include? member? has_key?].each do |key_alias|
|
95
95
|
it "is aliased as #{key_alias}" do
|
96
96
|
expect(h.send(key_alias.to_sym, :foo)).to be(true)
|
97
97
|
expect(h.send(key_alias.to_sym, 'foo')).to be(true)
|
@@ -20,7 +20,7 @@ describe Hashie::Extensions::MethodReader do
|
|
20
20
|
end
|
21
21
|
|
22
22
|
it 'reads nil and false values out properly' do
|
23
|
-
h = subject.new(nil: nil, false: false)
|
23
|
+
h = subject.new(nil: nil, false: false) # rubocop:disable Lint/BooleanSymbol
|
24
24
|
expect(h.nil).to eq nil
|
25
25
|
expect(h.false).to eq false
|
26
26
|
end
|
@@ -168,21 +168,59 @@ describe Hashie::Extensions::MethodOverridingWriter do
|
|
168
168
|
end
|
169
169
|
|
170
170
|
it 'aliases the method with two leading underscores' do
|
171
|
-
expect(subject.__zip).to eq [[%w
|
171
|
+
expect(subject.__zip).to eq [[%w[zip a-dee-doo-dah]]]
|
172
172
|
end
|
173
173
|
|
174
174
|
it 'does not re-alias when overriding an already overridden method' do
|
175
175
|
subject.zip = 'test'
|
176
176
|
expect(subject.zip).to eq 'test'
|
177
|
-
expect(subject.__zip).to eq [[%w
|
177
|
+
expect(subject.__zip).to eq [[%w[zip test]]]
|
178
178
|
end
|
179
179
|
end
|
180
180
|
end
|
181
181
|
|
182
182
|
describe Hashie::Extensions::MethodAccessWithOverride do
|
183
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
|
+
|
184
191
|
klass = Class.new(Hash)
|
185
192
|
klass.send :include, Hashie::Extensions::MethodAccessWithOverride
|
186
|
-
|
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
|
187
225
|
end
|
188
226
|
end
|
@@ -14,7 +14,7 @@ shared_examples 'stringify_keys!' do
|
|
14
14
|
object[:abc] = 'abc'
|
15
15
|
object[123] = '123'
|
16
16
|
invoke :stringify_keys!
|
17
|
-
expect((object.keys & %w
|
17
|
+
expect((object.keys & %w[abc 123]).size).to eq 2
|
18
18
|
end
|
19
19
|
|
20
20
|
it 'converts nested instances of the same class' do
|
@@ -53,7 +53,7 @@ shared_examples 'stringify_keys' do
|
|
53
53
|
object[:abc] = 'def'
|
54
54
|
copy = invoke :stringify_keys
|
55
55
|
expect(object.keys).to eq [:abc]
|
56
|
-
expect(copy.keys).to eq %w
|
56
|
+
expect(copy.keys).to eq %w[abc]
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
@@ -71,7 +71,7 @@ describe Hashie::Extensions::StringifyKeys do
|
|
71
71
|
|
72
72
|
context 'class methods' do
|
73
73
|
subject { described_class }
|
74
|
-
let(:object) {
|
74
|
+
let(:object) { {} }
|
75
75
|
|
76
76
|
describe '.stringify_keys' do
|
77
77
|
include_examples 'stringify_keys'
|
@@ -113,7 +113,7 @@ describe Hashie do
|
|
113
113
|
end
|
114
114
|
|
115
115
|
subject { described_class }
|
116
|
-
let(:object) {
|
116
|
+
let(:object) { {} }
|
117
117
|
|
118
118
|
describe '.stringify_keys' do
|
119
119
|
include_examples 'stringify_keys'
|
@@ -14,7 +14,7 @@ shared_examples 'symbolize_keys!' do
|
|
14
14
|
object['abc'] = 'abc'
|
15
15
|
object['def'] = 'def'
|
16
16
|
invoke :symbolize_keys!
|
17
|
-
expect((object.keys & [
|
17
|
+
expect((object.keys & %i[abc def]).size).to eq 2
|
18
18
|
end
|
19
19
|
|
20
20
|
it 'converts nested instances of the same class' do
|
@@ -76,7 +76,7 @@ describe Hashie::Extensions::SymbolizeKeys do
|
|
76
76
|
|
77
77
|
context 'class methods' do
|
78
78
|
subject { described_class }
|
79
|
-
let(:object) {
|
79
|
+
let(:object) { {} }
|
80
80
|
|
81
81
|
describe '.symbolize_keys' do
|
82
82
|
include_examples 'symbolize_keys'
|
@@ -118,7 +118,7 @@ describe Hashie do
|
|
118
118
|
end
|
119
119
|
|
120
120
|
subject { described_class }
|
121
|
-
let(:object) {
|
121
|
+
let(:object) { {} }
|
122
122
|
|
123
123
|
describe '.symbolize_keys' do
|
124
124
|
include_examples 'symbolize_keys'
|