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.
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'