hashie 3.5.7 → 3.6.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.
- 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'
|