hashie 3.5.7 → 3.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +22 -0
  3. data/README.md +91 -22
  4. data/Rakefile +2 -2
  5. data/hashie.gemspec +1 -1
  6. data/lib/hashie/clash.rb +12 -1
  7. data/lib/hashie/dash.rb +41 -21
  8. data/lib/hashie/extensions/coercion.rb +5 -5
  9. data/lib/hashie/extensions/dash/property_translation.rb +49 -26
  10. data/lib/hashie/extensions/deep_fetch.rb +1 -1
  11. data/lib/hashie/extensions/deep_find.rb +2 -2
  12. data/lib/hashie/extensions/deep_locate.rb +4 -5
  13. data/lib/hashie/extensions/deep_merge.rb +8 -9
  14. data/lib/hashie/extensions/indifferent_access.rb +7 -5
  15. data/lib/hashie/extensions/mash/keep_original_keys.rb +3 -5
  16. data/lib/hashie/extensions/mash/safe_assignment.rb +1 -1
  17. data/lib/hashie/extensions/mash/symbolize_keys.rb +1 -1
  18. data/lib/hashie/extensions/method_access.rb +47 -17
  19. data/lib/hashie/extensions/parsers/yaml_erb_parser.rb +3 -1
  20. data/lib/hashie/extensions/strict_key_access.rb +8 -9
  21. data/lib/hashie/extensions/stringify_keys.rb +1 -1
  22. data/lib/hashie/extensions/symbolize_keys.rb +1 -1
  23. data/lib/hashie/hash.rb +4 -4
  24. data/lib/hashie/mash.rb +22 -22
  25. data/lib/hashie/rash.rb +5 -5
  26. data/lib/hashie/version.rb +1 -1
  27. data/spec/hashie/array_spec.rb +1 -1
  28. data/spec/hashie/dash_spec.rb +27 -2
  29. data/spec/hashie/extensions/coercion_spec.rb +20 -12
  30. data/spec/hashie/extensions/deep_locate_spec.rb +1 -1
  31. data/spec/hashie/extensions/deep_merge_spec.rb +1 -1
  32. data/spec/hashie/extensions/indifferent_access_spec.rb +20 -7
  33. data/spec/hashie/extensions/indifferent_access_with_rails_hwia_spec.rb +5 -5
  34. data/spec/hashie/extensions/method_access_spec.rb +42 -4
  35. data/spec/hashie/extensions/stringify_keys_spec.rb +4 -4
  36. data/spec/hashie/extensions/symbolize_keys_spec.rb +3 -3
  37. data/spec/hashie/mash_spec.rb +16 -8
  38. data/spec/hashie/parsers/yaml_erb_parser_spec.rb +3 -3
  39. data/spec/hashie/rash_spec.rb +2 -2
  40. data/spec/hashie/trash_spec.rb +61 -1
  41. data/spec/integration/elasticsearch/integration_spec.rb +40 -0
  42. data/spec/integration/omniauth-oauth2/app.rb +3 -4
  43. data/spec/integration/omniauth-oauth2/some_site.rb +2 -2
  44. data/spec/integration/rails/app.rb +3 -4
  45. metadata +5 -3
@@ -64,7 +64,7 @@ module Hashie
64
64
  # Raise (or yield) unless something matches the key.
65
65
  #
66
66
  def fetch(*args)
67
- fail ArgumentError, "Expected 1-2 arguments, got #{args.length}" \
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
- fail KeyError, "key not found: #{key.inspect}"
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?(*args)
132
- @hash.respond_to?(*args)
131
+ def respond_to_missing?(method_name, _include_private = false)
132
+ @hash.respond_to?(method_name)
133
133
  end
134
134
 
135
135
  private
@@ -1,3 +1,3 @@
1
1
  module Hashie
2
- VERSION = '3.5.7'
2
+ VERSION = '3.6.0'.freeze
3
3
  end
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
  describe Array do
4
4
  with_minimum_ruby('2.3.0') do
5
5
  describe '#dig' do
6
- let(:array) { Hashie::Array.new([:a, :b, :c]) }
6
+ let(:array) { Hashie::Array.new(%i[a b c]) }
7
7
 
8
8
  it 'works with a string index' do
9
9
  expect(array.dig('0')).to eq(:a)
@@ -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([:first_name, :email, :count])
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 [:count, :first_name]
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('bar', 'bar2')
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('bar', 'bar2'))
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('bar', 'bar2')
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 = if Hashie::Extensions::RubyVersion.new(RUBY_VERSION) >= Hashie::Extensions::RubyVersion.new('2.4.0')
562
- Integer
563
- else
564
- Fixnum
565
- end
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
- subject.coerce_value Integer, String
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? Integer
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(true t yes y 1)
614
- false_values = %w(false f no n 0)
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
- !object.extend(described_class).deep_locate(:match).empty?
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 change { h2[:e][:e1] }
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
- alias_method :build, :new
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
- alias_method :build, :[]
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
- alias_method :build, :try_convert
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(:cat => 'meow')
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.merge!(:cat => 'meow')
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(bar qux)
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(include? member? has_key?).each do |key_alias|
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
- alias_method :build, :new
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
- alias_method :build, :[]
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
- alias_method :build, :try_convert
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(bar qux)
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(include? member? has_key?).each do |key_alias|
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(zip a-dee-doo-dah)]]
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(zip test)]]
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
- expect((klass.ancestors & [Hashie::Extensions::MethodReader, Hashie::Extensions::MethodOverridingWriter, Hashie::Extensions::MethodQuery]).size).to eq 3
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(abc 123)).size).to eq 2
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(abc)
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) { Hash.new }
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) { Hash.new }
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 & [:abc, :def]).size).to eq 2
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) { Hash.new }
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) { Hash.new }
121
+ let(:object) { {} }
122
122
 
123
123
  describe '.symbolize_keys' do
124
124
  include_examples 'symbolize_keys'