hashie 4.0.0 → 4.1.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 (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