hashie 3.4.3 → 5.0.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 +516 -129
- data/CONTRIBUTING.md +24 -7
- data/LICENSE +1 -1
- data/README.md +408 -50
- data/Rakefile +18 -1
- data/UPGRADING.md +157 -7
- data/hashie.gemspec +14 -8
- data/lib/hashie/array.rb +21 -0
- data/lib/hashie/clash.rb +24 -12
- data/lib/hashie/dash.rb +56 -31
- data/lib/hashie/extensions/active_support/core_ext/hash.rb +14 -0
- data/lib/hashie/extensions/array/pretty_inspect.rb +19 -0
- data/lib/hashie/extensions/coercion.rb +30 -17
- data/lib/hashie/extensions/dash/indifferent_access.rb +30 -1
- data/lib/hashie/extensions/dash/predefined_values.rb +88 -0
- data/lib/hashie/extensions/dash/property_translation.rb +59 -28
- data/lib/hashie/extensions/deep_fetch.rb +5 -3
- data/lib/hashie/extensions/deep_find.rb +14 -5
- data/lib/hashie/extensions/deep_locate.rb +40 -21
- data/lib/hashie/extensions/deep_merge.rb +26 -10
- data/lib/hashie/extensions/ignore_undeclared.rb +6 -4
- data/lib/hashie/extensions/indifferent_access.rb +49 -8
- data/lib/hashie/extensions/key_conflict_warning.rb +55 -0
- data/lib/hashie/extensions/mash/define_accessors.rb +90 -0
- data/lib/hashie/extensions/mash/keep_original_keys.rb +53 -0
- data/lib/hashie/extensions/mash/permissive_respond_to.rb +61 -0
- data/lib/hashie/extensions/mash/safe_assignment.rb +3 -1
- data/lib/hashie/extensions/mash/symbolize_keys.rb +38 -0
- data/lib/hashie/extensions/method_access.rb +77 -19
- data/lib/hashie/extensions/parsers/yaml_erb_parser.rb +29 -5
- data/lib/hashie/extensions/ruby_version.rb +60 -0
- data/lib/hashie/extensions/ruby_version_check.rb +21 -0
- data/lib/hashie/extensions/strict_key_access.rb +16 -13
- data/lib/hashie/extensions/stringify_keys.rb +1 -1
- data/lib/hashie/extensions/symbolize_keys.rb +13 -2
- data/lib/hashie/hash.rb +18 -11
- data/lib/hashie/logger.rb +18 -0
- data/lib/hashie/mash.rb +177 -43
- data/lib/hashie/railtie.rb +21 -0
- data/lib/hashie/rash.rb +7 -7
- data/lib/hashie/utils.rb +44 -0
- data/lib/hashie/version.rb +1 -1
- data/lib/hashie.rb +33 -17
- metadata +28 -95
- data/spec/hashie/clash_spec.rb +0 -48
- data/spec/hashie/dash_spec.rb +0 -513
- data/spec/hashie/extensions/autoload_spec.rb +0 -24
- data/spec/hashie/extensions/coercion_spec.rb +0 -625
- data/spec/hashie/extensions/dash/coercion_spec.rb +0 -13
- data/spec/hashie/extensions/dash/indifferent_access_spec.rb +0 -84
- data/spec/hashie/extensions/deep_fetch_spec.rb +0 -97
- data/spec/hashie/extensions/deep_find_spec.rb +0 -45
- data/spec/hashie/extensions/deep_locate_spec.rb +0 -124
- data/spec/hashie/extensions/deep_merge_spec.rb +0 -65
- data/spec/hashie/extensions/ignore_undeclared_spec.rb +0 -46
- data/spec/hashie/extensions/indifferent_access_spec.rb +0 -219
- data/spec/hashie/extensions/indifferent_access_with_rails_hwia_spec.rb +0 -208
- data/spec/hashie/extensions/key_conversion_spec.rb +0 -12
- data/spec/hashie/extensions/mash/safe_assignment_spec.rb +0 -50
- data/spec/hashie/extensions/merge_initializer_spec.rb +0 -23
- data/spec/hashie/extensions/method_access_spec.rb +0 -184
- data/spec/hashie/extensions/strict_key_access_spec.rb +0 -110
- data/spec/hashie/extensions/stringify_keys_spec.rb +0 -124
- data/spec/hashie/extensions/symbolize_keys_spec.rb +0 -129
- data/spec/hashie/hash_spec.rb +0 -84
- data/spec/hashie/mash_spec.rb +0 -680
- data/spec/hashie/parsers/yaml_erb_parser_spec.rb +0 -29
- data/spec/hashie/rash_spec.rb +0 -77
- data/spec/hashie/trash_spec.rb +0 -268
- data/spec/hashie/version_spec.rb +0 -7
- data/spec/spec_helper.rb +0 -16
- data/spec/support/module_context.rb +0 -11
@@ -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,45 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Hashie::Extensions::DeepFind do
|
4
|
-
subject { Class.new(Hash) { include Hashie::Extensions::DeepFind } }
|
5
|
-
let(:hash) do
|
6
|
-
{
|
7
|
-
library: {
|
8
|
-
books: [
|
9
|
-
{ title: 'Call of the Wild' },
|
10
|
-
{ title: 'Moby Dick' }
|
11
|
-
],
|
12
|
-
shelves: nil,
|
13
|
-
location: {
|
14
|
-
address: '123 Library St.',
|
15
|
-
title: 'Main Library'
|
16
|
-
}
|
17
|
-
}
|
18
|
-
}
|
19
|
-
end
|
20
|
-
let(:instance) { subject.new.update(hash) }
|
21
|
-
|
22
|
-
describe '#deep_find' do
|
23
|
-
it 'detects a value from a nested hash' do
|
24
|
-
expect(instance.deep_find(:address)).to eq('123 Library St.')
|
25
|
-
end
|
26
|
-
|
27
|
-
it 'detects a value from a nested array' do
|
28
|
-
expect(instance.deep_find(:title)).to eq('Call of the Wild')
|
29
|
-
end
|
30
|
-
|
31
|
-
it 'returns nil if it does not find a match' do
|
32
|
-
expect(instance.deep_find(:wahoo)).to be_nil
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
describe '#deep_find_all' do
|
37
|
-
it 'detects all values from a nested hash' do
|
38
|
-
expect(instance.deep_find_all(:title)).to eq(['Call of the Wild', 'Moby Dick', 'Main Library'])
|
39
|
-
end
|
40
|
-
|
41
|
-
it 'returns nil if it does not find any matches' do
|
42
|
-
expect(instance.deep_find_all(:wahoo)).to be_nil
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
@@ -1,124 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Hashie::Extensions::DeepLocate do
|
4
|
-
let(:hash) do
|
5
|
-
{
|
6
|
-
from: 0,
|
7
|
-
size: 25,
|
8
|
-
query: {
|
9
|
-
bool: {
|
10
|
-
must: [
|
11
|
-
{
|
12
|
-
query_string: {
|
13
|
-
query: 'foobar',
|
14
|
-
default_operator: 'AND',
|
15
|
-
fields: [
|
16
|
-
'title^2',
|
17
|
-
'_all'
|
18
|
-
]
|
19
|
-
}
|
20
|
-
},
|
21
|
-
{
|
22
|
-
match: {
|
23
|
-
field_1: 'value_1'
|
24
|
-
}
|
25
|
-
},
|
26
|
-
{
|
27
|
-
range: {
|
28
|
-
lsr09: {
|
29
|
-
gte: 2014
|
30
|
-
}
|
31
|
-
}
|
32
|
-
}
|
33
|
-
],
|
34
|
-
should: [
|
35
|
-
{
|
36
|
-
match: {
|
37
|
-
field_2: 'value_2'
|
38
|
-
}
|
39
|
-
}
|
40
|
-
],
|
41
|
-
must_not: [
|
42
|
-
{
|
43
|
-
range: {
|
44
|
-
lsr10: {
|
45
|
-
gte: 2014
|
46
|
-
}
|
47
|
-
}
|
48
|
-
}
|
49
|
-
]
|
50
|
-
}
|
51
|
-
}
|
52
|
-
}
|
53
|
-
end
|
54
|
-
|
55
|
-
describe '.deep_locate' do
|
56
|
-
context 'if called with a non-callable comparator' do
|
57
|
-
it 'creates a key comparator on-th-fly' do
|
58
|
-
expect(described_class.deep_locate(:lsr10, hash)).to eq([hash[:query][:bool][:must_not][0][:range]])
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
it 'locates enumerables for which the given comparator returns true for at least one element' do
|
63
|
-
examples = [
|
64
|
-
[
|
65
|
-
->(key, _value, _object) { key == :fields },
|
66
|
-
[
|
67
|
-
hash[:query][:bool][:must].first[:query_string]
|
68
|
-
]
|
69
|
-
],
|
70
|
-
[
|
71
|
-
->(_key, value, _object) { value.is_a?(String) && value.include?('value') },
|
72
|
-
[
|
73
|
-
hash[:query][:bool][:must][1][:match],
|
74
|
-
hash[:query][:bool][:should][0][:match]
|
75
|
-
]
|
76
|
-
],
|
77
|
-
[
|
78
|
-
lambda do |_key, _value, object|
|
79
|
-
object.is_a?(Array) &&
|
80
|
-
!object.extend(described_class).deep_locate(:match).empty?
|
81
|
-
end,
|
82
|
-
[
|
83
|
-
hash[:query][:bool][:must],
|
84
|
-
hash[:query][:bool][:should]
|
85
|
-
]
|
86
|
-
]
|
87
|
-
]
|
88
|
-
|
89
|
-
examples.each do |comparator, expected_result|
|
90
|
-
expect(described_class.deep_locate(comparator, hash)).to eq(expected_result)
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
it 'returns an empty array if nothing was found' do
|
95
|
-
expect(described_class.deep_locate(:muff, foo: 'bar')).to eq([])
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
context 'if extending an existing object' do
|
100
|
-
let(:extended_hash) do
|
101
|
-
hash.extend(described_class)
|
102
|
-
end
|
103
|
-
|
104
|
-
it 'adds #deep_locate' do
|
105
|
-
expect(extended_hash.deep_locate(:bool)).to eq([hash[:query]])
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
context 'if included in a hash' do
|
110
|
-
let(:derived_hash_with_extension_included) do
|
111
|
-
Class.new(Hash) do
|
112
|
-
include Hashie::Extensions::DeepLocate
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
let(:instance) do
|
117
|
-
derived_hash_with_extension_included.new.update(hash)
|
118
|
-
end
|
119
|
-
|
120
|
-
it 'adds #deep_locate' do
|
121
|
-
expect(instance.deep_locate(:bool)).to eq([hash[:query]])
|
122
|
-
end
|
123
|
-
end
|
124
|
-
end
|
@@ -1,65 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Hashie::Extensions::DeepMerge do
|
4
|
-
class DeepMergeHash < Hash
|
5
|
-
include Hashie::Extensions::DeepMerge
|
6
|
-
end
|
7
|
-
|
8
|
-
subject { DeepMergeHash }
|
9
|
-
|
10
|
-
it 'should return initial hash for arguments that are not hash' do
|
11
|
-
hash = subject.new.merge(a: 'a')
|
12
|
-
expect(hash.deep_merge('abc')).to eq(hash)
|
13
|
-
end
|
14
|
-
|
15
|
-
context 'without &block' do
|
16
|
-
let(:h1) { subject.new.merge(a: 'a', a1: 42, b: 'b', c: { c1: 'c1', c2: { a: 'b' }, c3: { d1: 'd1' } }) }
|
17
|
-
let(:h2) { { a: 1, a1: 1, c: { c1: 2, c2: 'c2', c3: { d2: 'd2' } } } }
|
18
|
-
let(:expected_hash) { { a: 1, a1: 1, b: 'b', c: { c1: 2, c2: 'c2', c3: { d1: 'd1', d2: 'd2' } } } }
|
19
|
-
|
20
|
-
it 'deep merges two hashes' do
|
21
|
-
expect(h1.deep_merge(h2)).to eq expected_hash
|
22
|
-
end
|
23
|
-
|
24
|
-
it 'deep merges another hash in place via bang method' do
|
25
|
-
h1.deep_merge!(h2)
|
26
|
-
expect(h1).to eq expected_hash
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
context 'with &block' do
|
31
|
-
let(:h1) { subject.new.merge(a: 100, b: 200, c: { c1: 100 }) }
|
32
|
-
let(:h2) { { b: 250, c: { c1: 200 } } }
|
33
|
-
let(:expected_hash) { { a: 100, b: 450, c: { c1: 300 } } }
|
34
|
-
let(:block) { proc { |_, this_val, other_val| this_val + other_val } }
|
35
|
-
|
36
|
-
it 'deep merges two hashes' do
|
37
|
-
expect(h1.deep_merge(h2, &block)).to eq expected_hash
|
38
|
-
end
|
39
|
-
|
40
|
-
it 'deep merges another hash in place via bang method' do
|
41
|
-
h1.deep_merge!(h2, &block)
|
42
|
-
expect(h1).to eq expected_hash
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
context 'from extended object' do
|
47
|
-
subject { Hash }
|
48
|
-
let(:h1) { subject.new.merge(a: 100, c: { c1: 100 }).extend(Hashie::Extensions::DeepMerge) }
|
49
|
-
let(:h2) { { b: 250, c: { c1: 200 } } }
|
50
|
-
let(:expected_hash) { { a: 100, b: 250, c: { c1: 200 } } }
|
51
|
-
|
52
|
-
it 'does not raise error' do
|
53
|
-
expect { h1.deep_merge(h2) } .not_to raise_error
|
54
|
-
end
|
55
|
-
|
56
|
-
it 'deep merges two hashes' do
|
57
|
-
expect(h1.deep_merge(h2)).to eq expected_hash
|
58
|
-
end
|
59
|
-
|
60
|
-
it 'deep merges another hash in place via bang method' do
|
61
|
-
h1.deep_merge!(h2)
|
62
|
-
expect(h1).to eq expected_hash
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
@@ -1,46 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Hashie::Extensions::IgnoreUndeclared do
|
4
|
-
context 'included in Trash' do
|
5
|
-
class ForgivingTrash < Hashie::Trash
|
6
|
-
include Hashie::Extensions::IgnoreUndeclared
|
7
|
-
property :city
|
8
|
-
property :state, from: :provence
|
9
|
-
end
|
10
|
-
|
11
|
-
subject { ForgivingTrash }
|
12
|
-
|
13
|
-
it 'silently ignores undeclared properties on initialization' do
|
14
|
-
expect { subject.new(city: 'Toronto', provence: 'ON', country: 'Canada') }.to_not raise_error
|
15
|
-
end
|
16
|
-
|
17
|
-
it 'works with translated properties (with symbol keys)' do
|
18
|
-
expect(subject.new(provence: 'Ontario').state).to eq('Ontario')
|
19
|
-
end
|
20
|
-
|
21
|
-
it 'works with translated properties (with string keys)' do
|
22
|
-
expect(subject.new(provence: 'Ontario').state).to eq('Ontario')
|
23
|
-
end
|
24
|
-
|
25
|
-
it 'requires properties to be declared on assignment' do
|
26
|
-
hash = subject.new(city: 'Toronto')
|
27
|
-
expect { hash.country = 'Canada' }.to raise_error(NoMethodError)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
context 'combined with DeepMerge' do
|
32
|
-
class ForgivingTrashWithMerge < Hashie::Trash
|
33
|
-
include Hashie::Extensions::DeepMerge
|
34
|
-
include Hashie::Extensions::IgnoreUndeclared
|
35
|
-
property :some_key
|
36
|
-
end
|
37
|
-
|
38
|
-
it 'deep merges' do
|
39
|
-
class ForgivingTrashWithMergeAndProperty < ForgivingTrashWithMerge
|
40
|
-
property :some_other_key
|
41
|
-
end
|
42
|
-
hash = ForgivingTrashWithMergeAndProperty.new(some_ignored_key: 17, some_key: 12)
|
43
|
-
expect(hash.deep_merge(some_other_key: 55, some_ignored_key: 18)).to eq(some_key: 12, some_other_key: 55)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
@@ -1,219 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Hashie::Extensions::IndifferentAccess do
|
4
|
-
class IndifferentHashWithMergeInitializer < Hash
|
5
|
-
include Hashie::Extensions::MergeInitializer
|
6
|
-
include Hashie::Extensions::IndifferentAccess
|
7
|
-
|
8
|
-
class << self
|
9
|
-
alias_method :build, :new
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
class IndifferentHashWithArrayInitializer < Hash
|
14
|
-
include Hashie::Extensions::IndifferentAccess
|
15
|
-
|
16
|
-
class << self
|
17
|
-
alias_method :build, :[]
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
class IndifferentHashWithTryConvertInitializer < Hash
|
22
|
-
include Hashie::Extensions::IndifferentAccess
|
23
|
-
|
24
|
-
class << self
|
25
|
-
alias_method :build, :try_convert
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
class IndifferentHashWithDash < Hashie::Dash
|
30
|
-
include Hashie::Extensions::IndifferentAccess
|
31
|
-
property :foo
|
32
|
-
end
|
33
|
-
|
34
|
-
describe 'when included in dash' do
|
35
|
-
let(:params) { { foo: 'bar' } }
|
36
|
-
subject { IndifferentHashWithDash.new(params) }
|
37
|
-
|
38
|
-
it 'initialize with a symbol' do
|
39
|
-
expect(subject.foo).to eq params[:foo]
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
shared_examples_for 'hash with indifferent access' do
|
44
|
-
it 'is able to access via string or symbol' do
|
45
|
-
h = subject.build(abc: 123)
|
46
|
-
expect(h[:abc]).to eq 123
|
47
|
-
expect(h['abc']).to eq 123
|
48
|
-
end
|
49
|
-
|
50
|
-
describe '#values_at' do
|
51
|
-
it 'indifferently finds values' do
|
52
|
-
h = subject.build(:foo => 'bar', 'baz' => 'qux')
|
53
|
-
expect(h.values_at('foo', :baz)).to eq %w(bar qux)
|
54
|
-
end
|
55
|
-
|
56
|
-
it 'returns the same instance of the hash that was set' do
|
57
|
-
hash = Hash.new
|
58
|
-
h = subject.build(foo: hash)
|
59
|
-
expect(h.values_at(:foo)[0]).to be(hash)
|
60
|
-
end
|
61
|
-
|
62
|
-
it 'returns the same instance of the array that was set' do
|
63
|
-
array = Array.new
|
64
|
-
h = subject.build(foo: array)
|
65
|
-
expect(h.values_at(:foo)[0]).to be(array)
|
66
|
-
end
|
67
|
-
|
68
|
-
it 'returns the same instance of the string that was set' do
|
69
|
-
str = 'my string'
|
70
|
-
h = subject.build(foo: str)
|
71
|
-
expect(h.values_at(:foo)[0]).to be(str)
|
72
|
-
end
|
73
|
-
|
74
|
-
it 'returns the same instance of the object that was set' do
|
75
|
-
object = Object.new
|
76
|
-
h = subject.build(foo: object)
|
77
|
-
expect(h.values_at(:foo)[0]).to be(object)
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
describe '#fetch' do
|
82
|
-
it 'works like normal fetch, but indifferent' do
|
83
|
-
h = subject.build(foo: 'bar')
|
84
|
-
expect(h.fetch(:foo)).to eq h.fetch('foo')
|
85
|
-
expect(h.fetch(:foo)).to eq 'bar'
|
86
|
-
end
|
87
|
-
|
88
|
-
it 'returns the same instance of the hash that was set' do
|
89
|
-
hash = Hash.new
|
90
|
-
h = subject.build(foo: hash)
|
91
|
-
expect(h.fetch(:foo)).to be(hash)
|
92
|
-
end
|
93
|
-
|
94
|
-
it 'returns the same instance of the array that was set' do
|
95
|
-
array = Array.new
|
96
|
-
h = subject.build(foo: array)
|
97
|
-
expect(h.fetch(:foo)).to be(array)
|
98
|
-
end
|
99
|
-
|
100
|
-
it 'returns the same instance of the string that was set' do
|
101
|
-
str = 'my string'
|
102
|
-
h = subject.build(foo: str)
|
103
|
-
expect(h.fetch(:foo)).to be(str)
|
104
|
-
end
|
105
|
-
|
106
|
-
it 'returns the same instance of the object that was set' do
|
107
|
-
object = Object.new
|
108
|
-
h = subject.build(foo: object)
|
109
|
-
expect(h.fetch(:foo)).to be(object)
|
110
|
-
end
|
111
|
-
|
112
|
-
it 'yields with key name if key does not exists' do
|
113
|
-
h = subject.build(a: 0)
|
114
|
-
expect(h.fetch(:foo) { |key| ['default for', key] }).to eq ['default for', 'foo']
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
describe '#delete' do
|
119
|
-
it 'deletes indifferently' do
|
120
|
-
h = subject.build(:foo => 'bar', 'baz' => 'qux')
|
121
|
-
h.delete('foo')
|
122
|
-
h.delete(:baz)
|
123
|
-
expect(h).to be_empty
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
describe '#key?' do
|
128
|
-
let(:h) { subject.build(foo: 'bar') }
|
129
|
-
|
130
|
-
it 'finds it indifferently' do
|
131
|
-
expect(h).to be_key(:foo)
|
132
|
-
expect(h).to be_key('foo')
|
133
|
-
end
|
134
|
-
|
135
|
-
%w(include? member? has_key?).each do |key_alias|
|
136
|
-
it "is aliased as #{key_alias}" do
|
137
|
-
expect(h.send(key_alias.to_sym, :foo)).to be(true)
|
138
|
-
expect(h.send(key_alias.to_sym, 'foo')).to be(true)
|
139
|
-
end
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
describe '#update' do
|
144
|
-
let(:h) { subject.build(foo: 'bar') }
|
145
|
-
|
146
|
-
it 'allows keys to be indifferent still' do
|
147
|
-
h.update(baz: 'qux')
|
148
|
-
expect(h['foo']).to eq 'bar'
|
149
|
-
expect(h['baz']).to eq 'qux'
|
150
|
-
end
|
151
|
-
|
152
|
-
it 'recursively injects indifference into sub-hashes' do
|
153
|
-
h.update(baz: { qux: 'abc' })
|
154
|
-
expect(h['baz']['qux']).to eq 'abc'
|
155
|
-
end
|
156
|
-
|
157
|
-
it 'does not change the ancestors of the injected object class' do
|
158
|
-
h.update(baz: { qux: 'abc' })
|
159
|
-
expect(Hash.new).not_to be_respond_to(:indifferent_access?)
|
160
|
-
end
|
161
|
-
end
|
162
|
-
|
163
|
-
describe '#replace' do
|
164
|
-
let(:h) { subject.build(foo: 'bar').replace(bar: 'baz', hi: 'bye') }
|
165
|
-
|
166
|
-
it 'returns self' do
|
167
|
-
expect(h).to be_a(subject)
|
168
|
-
end
|
169
|
-
|
170
|
-
it 'removes old keys' do
|
171
|
-
[:foo, 'foo'].each do |k|
|
172
|
-
expect(h[k]).to be_nil
|
173
|
-
expect(h.key?(k)).to be_falsy
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
|
-
it 'creates new keys with indifferent access' do
|
178
|
-
[:bar, 'bar', :hi, 'hi'].each { |k| expect(h.key?(k)).to be_truthy }
|
179
|
-
expect(h[:bar]).to eq 'baz'
|
180
|
-
expect(h['bar']).to eq 'baz'
|
181
|
-
expect(h[:hi]).to eq 'bye'
|
182
|
-
expect(h['hi']).to eq 'bye'
|
183
|
-
end
|
184
|
-
end
|
185
|
-
|
186
|
-
describe '#try_convert' do
|
187
|
-
describe 'with conversion' do
|
188
|
-
let(:h) { subject.try_convert(foo: 'bar') }
|
189
|
-
|
190
|
-
it 'is a subject' do
|
191
|
-
expect(h).to be_a(subject)
|
192
|
-
end
|
193
|
-
end
|
194
|
-
|
195
|
-
describe 'without conversion' do
|
196
|
-
let(:h) { subject.try_convert('{ :foo => bar }') }
|
197
|
-
|
198
|
-
it 'is nil' do
|
199
|
-
expect(h).to be_nil
|
200
|
-
end
|
201
|
-
end
|
202
|
-
end
|
203
|
-
end
|
204
|
-
|
205
|
-
describe 'with merge initializer' do
|
206
|
-
subject { IndifferentHashWithMergeInitializer }
|
207
|
-
it_should_behave_like 'hash with indifferent access'
|
208
|
-
end
|
209
|
-
|
210
|
-
describe 'with array initializer' do
|
211
|
-
subject { IndifferentHashWithArrayInitializer }
|
212
|
-
it_should_behave_like 'hash with indifferent access'
|
213
|
-
end
|
214
|
-
|
215
|
-
describe 'with try convert initializer' do
|
216
|
-
subject { IndifferentHashWithTryConvertInitializer }
|
217
|
-
it_should_behave_like 'hash with indifferent access'
|
218
|
-
end
|
219
|
-
end
|