hashie 4.0.0 → 4.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +213 -187
  3. data/CONTRIBUTING.md +13 -6
  4. data/README.md +33 -9
  5. data/UPGRADING.md +5 -5
  6. data/hashie.gemspec +11 -6
  7. data/lib/hashie.rb +1 -0
  8. data/lib/hashie/extensions/dash/property_translation.rb +1 -1
  9. data/lib/hashie/extensions/deep_merge.rb +18 -1
  10. data/lib/hashie/extensions/mash/permissive_respond_to.rb +61 -0
  11. data/lib/hashie/extensions/parsers/yaml_erb_parser.rb +19 -2
  12. data/lib/hashie/extensions/ruby_version_check.rb +5 -1
  13. data/lib/hashie/mash.rb +31 -26
  14. data/lib/hashie/utils.rb +28 -0
  15. data/lib/hashie/version.rb +1 -1
  16. metadata +16 -131
  17. data/spec/hashie/array_spec.rb +0 -29
  18. data/spec/hashie/clash_spec.rb +0 -70
  19. data/spec/hashie/dash_spec.rb +0 -608
  20. data/spec/hashie/extensions/autoload_spec.rb +0 -24
  21. data/spec/hashie/extensions/coercion_spec.rb +0 -648
  22. data/spec/hashie/extensions/dash/coercion_spec.rb +0 -13
  23. data/spec/hashie/extensions/dash/indifferent_access_spec.rb +0 -84
  24. data/spec/hashie/extensions/deep_fetch_spec.rb +0 -97
  25. data/spec/hashie/extensions/deep_find_spec.rb +0 -144
  26. data/spec/hashie/extensions/deep_locate_spec.rb +0 -138
  27. data/spec/hashie/extensions/deep_merge_spec.rb +0 -74
  28. data/spec/hashie/extensions/ignore_undeclared_spec.rb +0 -48
  29. data/spec/hashie/extensions/indifferent_access_spec.rb +0 -295
  30. data/spec/hashie/extensions/indifferent_access_with_rails_hwia_spec.rb +0 -208
  31. data/spec/hashie/extensions/key_conversion_spec.rb +0 -12
  32. data/spec/hashie/extensions/mash/define_accessors_spec.rb +0 -90
  33. data/spec/hashie/extensions/mash/keep_original_keys_spec.rb +0 -46
  34. data/spec/hashie/extensions/mash/safe_assignment_spec.rb +0 -50
  35. data/spec/hashie/extensions/mash/symbolize_keys_spec.rb +0 -39
  36. data/spec/hashie/extensions/merge_initializer_spec.rb +0 -23
  37. data/spec/hashie/extensions/method_access_spec.rb +0 -233
  38. data/spec/hashie/extensions/strict_key_access_spec.rb +0 -109
  39. data/spec/hashie/extensions/stringify_keys_spec.rb +0 -124
  40. data/spec/hashie/extensions/symbolize_keys_spec.rb +0 -131
  41. data/spec/hashie/hash_spec.rb +0 -123
  42. data/spec/hashie/mash_spec.rb +0 -1077
  43. data/spec/hashie/parsers/yaml_erb_parser_spec.rb +0 -46
  44. data/spec/hashie/rash_spec.rb +0 -83
  45. data/spec/hashie/trash_spec.rb +0 -334
  46. data/spec/hashie/utils_spec.rb +0 -25
  47. data/spec/hashie/version_spec.rb +0 -7
  48. data/spec/hashie_spec.rb +0 -13
  49. data/spec/integration/elasticsearch/integration_spec.rb +0 -41
  50. data/spec/integration/omniauth-oauth2/app.rb +0 -52
  51. data/spec/integration/omniauth-oauth2/integration_spec.rb +0 -26
  52. data/spec/integration/omniauth-oauth2/some_site.rb +0 -38
  53. data/spec/integration/omniauth/app.rb +0 -11
  54. data/spec/integration/omniauth/integration_spec.rb +0 -38
  55. data/spec/integration/rails-without-dependency/integration_spec.rb +0 -15
  56. data/spec/integration/rails/app.rb +0 -40
  57. data/spec/integration/rails/integration_spec.rb +0 -47
  58. data/spec/spec_helper.rb +0 -23
  59. data/spec/support/integration_specs.rb +0 -36
  60. data/spec/support/logger.rb +0 -24
  61. data/spec/support/module_context.rb +0 -11
  62. data/spec/support/ruby_version_check.rb +0 -6
@@ -1,13 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Hashie::Extensions::Dash::Coercion do
4
- class DashWithCoercion < Hashie::Dash
5
- include Hashie::Extensions::Dash::Coercion
6
-
7
- property :type, coerce: Symbol
8
- end
9
-
10
- it 'does the coercion of properties' do
11
- expect(DashWithCoercion.new(type: 'something')).to eq(type: :something)
12
- end
13
- end
@@ -1,84 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Hashie::Extensions::Dash::IndifferentAccess do
4
- class TrashWithIndifferentAccess < Hashie::Trash
5
- include Hashie::Extensions::Dash::IndifferentAccess
6
- property :per_page, transform_with: ->(v) { v.to_i }
7
- property :total, from: :total_pages
8
- end
9
-
10
- class DashWithIndifferentAccess < Hashie::Dash
11
- include Hashie::Extensions::Dash::IndifferentAccess
12
- property :name
13
- end
14
-
15
- context 'when included in Trash' do
16
- let(:params) { { per_page: '1', total_pages: 2 } }
17
- subject { TrashWithIndifferentAccess.new(params) }
18
-
19
- it 'gets the expected behaviour' do
20
- expect(subject.per_page).to eq params[:per_page].to_i
21
- expect(subject.total).to eq params[:total_pages]
22
- end
23
- end
24
-
25
- context 'when included in Dash' do
26
- let(:patch) { Hashie::Extensions::Dash::IndifferentAccess::ClassMethods }
27
- let(:dash_class) { Class.new(Hashie::Dash) }
28
-
29
- it 'extends with the patch once' do
30
- expect(patch).to receive(:extended).with(dash_class).once
31
- dash_class.send(:include, Hashie::Extensions::Dash::IndifferentAccess)
32
- end
33
- end
34
-
35
- context 'initialized with' do
36
- it 'string' do
37
- instance = DashWithIndifferentAccess.new('name' => 'Name')
38
- expect(instance.name).to eq('Name')
39
- expect(instance['name']).to eq('Name')
40
- expect(instance[:name]).to eq('Name')
41
- expect(instance.inspect).to eq('#<DashWithIndifferentAccess name="Name">')
42
- expect(instance.to_hash).to eq('name' => 'Name')
43
- end
44
-
45
- it 'key' do
46
- instance = DashWithIndifferentAccess.new(name: 'Name')
47
- expect(instance.name).to eq('Name')
48
- expect(instance['name']).to eq('Name')
49
- expect(instance[:name]).to eq('Name')
50
- expect(instance.inspect).to eq('#<DashWithIndifferentAccess name="Name">')
51
- expect(instance.to_hash).to eq('name' => 'Name')
52
- end
53
- end
54
-
55
- it 'updates' do
56
- instance = DashWithIndifferentAccess.new
57
- instance['name'] = 'Updated String'
58
- expect(instance.name).to eq('Updated String')
59
- instance[:name] = 'Updated Symbol'
60
- expect(instance.name).to eq('Updated Symbol')
61
- instance.name = 'Updated Method'
62
- expect(instance.name).to eq('Updated Method')
63
- end
64
-
65
- context 'initialized with both prefers last assignment' do
66
- it 'string, then symbol' do
67
- instance = DashWithIndifferentAccess.new('name' => 'First', name: 'Last')
68
- expect(instance.name).to eq('Last')
69
- expect(instance['name']).to eq('Last')
70
- expect(instance[:name]).to eq('Last')
71
- expect(instance.inspect).to eq('#<DashWithIndifferentAccess name="Last">')
72
- expect(instance.to_hash).to eq('name' => 'Last')
73
- end
74
-
75
- it 'symbol then string' do
76
- instance = DashWithIndifferentAccess.new(name: 'Last', 'name' => 'First')
77
- expect(instance.name).to eq('First')
78
- expect(instance['name']).to eq('First')
79
- expect(instance[:name]).to eq('First')
80
- expect(instance.inspect).to eq('#<DashWithIndifferentAccess name="First">')
81
- expect(instance.to_hash).to eq('name' => 'First')
82
- end
83
- end
84
- end
@@ -1,97 +0,0 @@
1
- require 'spec_helper'
2
-
3
- module Hashie
4
- module Extensions
5
- describe DeepFetch do
6
- subject { Class.new(Hash) { include Hashie::Extensions::DeepFetch } }
7
- let(:hash) do
8
- {
9
- library: {
10
- books: [
11
- { title: 'Call of the Wild' },
12
- { title: 'Moby Dick' }
13
- ],
14
- shelves: nil,
15
- location: {
16
- address: '123 Library St.'
17
- }
18
- }
19
- }
20
- end
21
- let(:instance) { subject.new.update(hash) }
22
-
23
- describe '#deep_fetch' do
24
- it 'extracts a value from a nested hash' do
25
- expect(instance.deep_fetch(:library, :location, :address)).to eq('123 Library St.')
26
- end
27
-
28
- it 'extracts a value from a nested array' do
29
- expect(instance.deep_fetch(:library, :books, 1, :title)).to eq('Moby Dick')
30
- end
31
-
32
- context 'when one of the keys is not present' do
33
- context 'when a block is provided' do
34
- it 'returns the value of the block' do
35
- value = instance.deep_fetch(:library, :unknown_key, :location) { 'block value' }
36
- expect(value).to eq('block value')
37
- end
38
- end
39
-
40
- context 'when a block is not provided' do
41
- context 'when the nested object is an array' do
42
- it 'raises an UndefinedPathError' do
43
- expect do
44
- instance.deep_fetch(:library, :books, 2)
45
- end.to(
46
- raise_error(
47
- DeepFetch::UndefinedPathError,
48
- 'Could not fetch path (library > books > 2) at 2'
49
- )
50
- )
51
- end
52
- end
53
-
54
- context 'when the nested object is a hash' do
55
- it 'raises a UndefinedPathError' do
56
- expect do
57
- instance.deep_fetch(:library, :location, :unknown_key)
58
- end.to(
59
- raise_error(
60
- DeepFetch::UndefinedPathError,
61
- 'Could not fetch path (library > location > unknown_key) at unknown_key'
62
- )
63
- )
64
- end
65
- end
66
-
67
- context 'when the nested object is missing' do
68
- it 'raises an UndefinedPathError' do
69
- expect do
70
- instance.deep_fetch(:library, :unknown_key, :books)
71
- end.to(
72
- raise_error(
73
- DeepFetch::UndefinedPathError,
74
- 'Could not fetch path (library > unknown_key > books) at unknown_key'
75
- )
76
- )
77
- end
78
- end
79
-
80
- context 'when the nested object is nil' do
81
- it 'raises an UndefinedPathError' do
82
- expect do
83
- instance.deep_fetch(:library, :shelves, :address)
84
- end.to(
85
- raise_error(
86
- DeepFetch::UndefinedPathError,
87
- 'Could not fetch path (library > shelves > address) at address'
88
- )
89
- )
90
- end
91
- end
92
- end
93
- end
94
- end
95
- end
96
- end
97
- end
@@ -1,144 +0,0 @@
1
- require 'spec_helper'
2
- require 'active_support/core_ext/hash/indifferent_access'
3
-
4
- describe Hashie::Extensions::DeepFind do
5
- subject { Class.new(Hash) { include Hashie::Extensions::DeepFind } }
6
- let(:hash) do
7
- {
8
- library: {
9
- books: [
10
- { title: 'Call of the Wild' },
11
- { title: 'Moby Dick' }
12
- ],
13
- shelves: nil,
14
- location: {
15
- address: '123 Library St.',
16
- title: 'Main Library'
17
- }
18
- }
19
- }
20
- end
21
- let(:instance) { subject.new.update(hash) }
22
-
23
- describe '#deep_find' do
24
- it 'detects a value from a nested hash' do
25
- expect(instance.deep_find(:address)).to eq('123 Library St.')
26
- end
27
-
28
- it 'detects a value from a nested array' do
29
- expect(instance.deep_find(:title)).to eq('Call of the Wild')
30
- end
31
-
32
- it 'returns nil if it does not find a match' do
33
- expect(instance.deep_find(:wahoo)).to be_nil
34
- end
35
- end
36
-
37
- describe '#deep_find_all' do
38
- it 'detects all values from a nested hash' do
39
- expect(instance.deep_find_all(:title))
40
- .to eq(['Call of the Wild', 'Moby Dick', 'Main Library'])
41
- end
42
-
43
- it 'returns nil if it does not find any matches' do
44
- expect(instance.deep_find_all(:wahoo)).to be_nil
45
- end
46
-
47
- context 'when match value is hash itself' do
48
- let(:hash) do
49
- {
50
- title: {
51
- type: :string
52
- },
53
- library: {
54
- books: [
55
- { title: 'Call of the Wild' },
56
- { title: 'Moby Dick' }
57
- ],
58
- shelves: nil,
59
- location: {
60
- address: '123 Library St.',
61
- title: 'Main Library'
62
- }
63
- }
64
- }
65
- end
66
-
67
- it 'detects all values from a nested hash' do
68
- expect(instance.deep_find_all(:title))
69
- .to eq([{ type: :string }, 'Call of the Wild', 'Moby Dick', 'Main Library'])
70
- end
71
- end
72
- end
73
-
74
- context 'on an ActiveSupport::HashWithIndifferentAccess' do
75
- subject(:instance) { hash.with_indifferent_access.extend(Hashie::Extensions::DeepFind) }
76
-
77
- describe '#deep_find' do
78
- it 'indifferently detects a value from a nested hash' do
79
- expect(instance.deep_find(:address)).to eq('123 Library St.')
80
- expect(instance.deep_find('address')).to eq('123 Library St.')
81
- end
82
-
83
- it 'indifferently detects a value from a nested array' do
84
- expect(instance.deep_find(:title)).to eq('Call of the Wild')
85
- expect(instance.deep_find('title')).to eq('Call of the Wild')
86
- end
87
-
88
- it 'indifferently returns nil if it does not find a match' do
89
- expect(instance.deep_find(:wahoo)).to be_nil
90
- expect(instance.deep_find('wahoo')).to be_nil
91
- end
92
- end
93
-
94
- describe '#deep_find_all' do
95
- it 'indifferently detects all values from a nested hash' do
96
- expect(instance.deep_find_all(:title))
97
- .to eq(['Call of the Wild', 'Moby Dick', 'Main Library'])
98
- expect(instance.deep_find_all('title'))
99
- .to eq(['Call of the Wild', 'Moby Dick', 'Main Library'])
100
- end
101
-
102
- it 'indifferently returns nil if it does not find any matches' do
103
- expect(instance.deep_find_all(:wahoo)).to be_nil
104
- expect(instance.deep_find_all('wahoo')).to be_nil
105
- end
106
- end
107
- end
108
-
109
- context 'on a Hash including Hashie::Extensions::IndifferentAccess' do
110
- let(:klass) { Class.new(Hash) { include Hashie::Extensions::IndifferentAccess } }
111
- subject(:instance) { klass[hash.dup].extend(Hashie::Extensions::DeepFind) }
112
-
113
- describe '#deep_find' do
114
- it 'indifferently detects a value from a nested hash' do
115
- expect(instance.deep_find(:address)).to eq('123 Library St.')
116
- expect(instance.deep_find('address')).to eq('123 Library St.')
117
- end
118
-
119
- it 'indifferently detects a value from a nested array' do
120
- expect(instance.deep_find(:title)).to eq('Call of the Wild')
121
- expect(instance.deep_find('title')).to eq('Call of the Wild')
122
- end
123
-
124
- it 'indifferently returns nil if it does not find a match' do
125
- expect(instance.deep_find(:wahoo)).to be_nil
126
- expect(instance.deep_find('wahoo')).to be_nil
127
- end
128
- end
129
-
130
- describe '#deep_find_all' do
131
- it 'indifferently detects all values from a nested hash' do
132
- expect(instance.deep_find_all(:title))
133
- .to eq(['Call of the Wild', 'Moby Dick', 'Main Library'])
134
- expect(instance.deep_find_all('title'))
135
- .to eq(['Call of the Wild', 'Moby Dick', 'Main Library'])
136
- end
137
-
138
- it 'indifferently returns nil if it does not find any matches' do
139
- expect(instance.deep_find_all(:wahoo)).to be_nil
140
- expect(instance.deep_find_all('wahoo')).to be_nil
141
- end
142
- end
143
- end
144
- end
@@ -1,138 +0,0 @@
1
- require 'spec_helper'
2
- require 'active_support/core_ext/hash/indifferent_access'
3
-
4
- describe Hashie::Extensions::DeepLocate do
5
- let(:hash) do
6
- {
7
- from: 0,
8
- size: 25,
9
- query: {
10
- bool: {
11
- must: [
12
- {
13
- query_string: {
14
- query: 'foobar',
15
- default_operator: 'AND',
16
- fields: [
17
- 'title^2',
18
- '_all'
19
- ]
20
- }
21
- },
22
- {
23
- match: {
24
- field_1: 'value_1'
25
- }
26
- },
27
- {
28
- range: {
29
- lsr09: {
30
- gte: 2014
31
- }
32
- }
33
- }
34
- ],
35
- should: [
36
- {
37
- match: {
38
- field_2: 'value_2'
39
- }
40
- }
41
- ],
42
- must_not: [
43
- {
44
- range: {
45
- lsr10: {
46
- gte: 2014
47
- }
48
- }
49
- }
50
- ]
51
- }
52
- }
53
- }
54
- end
55
-
56
- describe '.deep_locate' do
57
- context 'if called with a non-callable comparator' do
58
- it 'creates a key comparator on-th-fly' do
59
- expect(described_class.deep_locate(:lsr10, hash))
60
- .to eq([hash[:query][:bool][:must_not][0][:range]])
61
- end
62
- end
63
-
64
- it 'locates enumerables for which the given comparator returns true for at least one element' do
65
- examples = [
66
- [
67
- ->(key, _value, _object) { key == :fields },
68
- [
69
- hash[:query][:bool][:must].first[:query_string]
70
- ]
71
- ],
72
- [
73
- ->(_key, value, _object) { value.is_a?(String) && value.include?('value') },
74
- [
75
- hash[:query][:bool][:must][1][:match],
76
- hash[:query][:bool][:should][0][:match]
77
- ]
78
- ],
79
- [
80
- lambda do |_key, _value, object|
81
- object.is_a?(Array) &&
82
- !object.extend(described_class).deep_locate(:match).empty?
83
- end,
84
- [
85
- hash[:query][:bool][:must],
86
- hash[:query][:bool][:should]
87
- ]
88
- ]
89
- ]
90
-
91
- examples.each do |comparator, expected_result|
92
- expect(described_class.deep_locate(comparator, hash)).to eq(expected_result)
93
- end
94
- end
95
-
96
- it 'returns an empty array if nothing was found' do
97
- expect(described_class.deep_locate(:muff, foo: 'bar')).to eq([])
98
- end
99
- end
100
-
101
- context 'if extending an existing object' do
102
- let(:extended_hash) do
103
- hash.extend(described_class)
104
- end
105
-
106
- it 'adds #deep_locate' do
107
- expect(extended_hash.deep_locate(:bool)).to eq([hash[:query]])
108
- end
109
- end
110
-
111
- context 'if included in a hash' do
112
- let(:derived_hash_with_extension_included) do
113
- Class.new(Hash) do
114
- include Hashie::Extensions::DeepLocate
115
- end
116
- end
117
-
118
- let(:instance) do
119
- derived_hash_with_extension_included.new.update(hash)
120
- end
121
-
122
- it 'adds #deep_locate' do
123
- expect(instance.deep_locate(:bool)).to eq([hash[:query]])
124
- end
125
- end
126
-
127
- context 'on an ActiveSupport::HashWithIndifferentAccess' do
128
- let(:instance) { hash.dup.with_indifferent_access }
129
-
130
- it 'can locate symbolic keys' do
131
- expect(described_class.deep_locate(:lsr10, instance)).to eq ['lsr10' => { 'gte' => 2014 }]
132
- end
133
-
134
- it 'can locate string keys' do
135
- expect(described_class.deep_locate('lsr10', instance)).to eq ['lsr10' => { 'gte' => 2014 }]
136
- end
137
- end
138
- end