hashie 2.1.2 → 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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +524 -59
- data/CONTRIBUTING.md +24 -7
- data/README.md +781 -90
- data/Rakefile +19 -2
- data/UPGRADING.md +245 -0
- data/hashie.gemspec +21 -13
- data/lib/hashie.rb +60 -21
- data/lib/hashie/array.rb +21 -0
- data/lib/hashie/clash.rb +24 -12
- data/lib/hashie/dash.rb +96 -33
- 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 +124 -18
- data/lib/hashie/extensions/dash/coercion.rb +25 -0
- data/lib/hashie/extensions/dash/indifferent_access.rb +56 -0
- data/lib/hashie/extensions/dash/property_translation.rb +191 -0
- data/lib/hashie/extensions/deep_fetch.rb +7 -5
- data/lib/hashie/extensions/deep_find.rb +69 -0
- data/lib/hashie/extensions/deep_locate.rb +113 -0
- data/lib/hashie/extensions/deep_merge.rb +35 -12
- data/lib/hashie/extensions/ignore_undeclared.rb +11 -5
- data/lib/hashie/extensions/indifferent_access.rb +28 -16
- data/lib/hashie/extensions/key_conflict_warning.rb +55 -0
- data/lib/hashie/extensions/key_conversion.rb +0 -82
- 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 +18 -0
- data/lib/hashie/extensions/mash/symbolize_keys.rb +38 -0
- data/lib/hashie/extensions/method_access.rb +154 -11
- data/lib/hashie/extensions/parsers/yaml_erb_parser.rb +48 -0
- data/lib/hashie/extensions/pretty_inspect.rb +19 -0
- 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 +77 -0
- data/lib/hashie/extensions/stringify_keys.rb +71 -0
- data/lib/hashie/extensions/symbolize_keys.rb +71 -0
- data/lib/hashie/hash.rb +27 -8
- data/lib/hashie/logger.rb +18 -0
- data/lib/hashie/mash.rb +235 -57
- data/lib/hashie/railtie.rb +21 -0
- data/lib/hashie/rash.rb +40 -16
- data/lib/hashie/trash.rb +2 -88
- data/lib/hashie/utils.rb +44 -0
- data/lib/hashie/version.rb +1 -1
- metadata +42 -81
- data/.gitignore +0 -9
- data/.rspec +0 -2
- data/.rubocop.yml +0 -36
- data/.travis.yml +0 -15
- data/Gemfile +0 -11
- data/Guardfile +0 -5
- data/lib/hashie/hash_extensions.rb +0 -47
- data/spec/hashie/clash_spec.rb +0 -48
- data/spec/hashie/dash_spec.rb +0 -338
- data/spec/hashie/extensions/coercion_spec.rb +0 -156
- data/spec/hashie/extensions/deep_fetch_spec.rb +0 -70
- data/spec/hashie/extensions/deep_merge_spec.rb +0 -22
- data/spec/hashie/extensions/ignore_undeclared_spec.rb +0 -23
- data/spec/hashie/extensions/indifferent_access_spec.rb +0 -152
- data/spec/hashie/extensions/key_conversion_spec.rb +0 -103
- data/spec/hashie/extensions/merge_initializer_spec.rb +0 -23
- data/spec/hashie/extensions/method_access_spec.rb +0 -121
- data/spec/hashie/hash_spec.rb +0 -66
- data/spec/hashie/mash_spec.rb +0 -467
- data/spec/hashie/rash_spec.rb +0 -44
- data/spec/hashie/trash_spec.rb +0 -193
- data/spec/hashie/version_spec.rb +0 -7
- data/spec/spec.opts +0 -3
- data/spec/spec_helper.rb +0 -8
@@ -1,23 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Hashie::Extensions::MergeInitializer do
|
4
|
-
class MergeInitializerHash < Hash
|
5
|
-
include Hashie::Extensions::MergeInitializer
|
6
|
-
end
|
7
|
-
|
8
|
-
subject { MergeInitializerHash }
|
9
|
-
|
10
|
-
it 'initializes with no arguments' do
|
11
|
-
expect(subject.new).to eq({})
|
12
|
-
end
|
13
|
-
|
14
|
-
it 'initializes with a hash' do
|
15
|
-
expect(subject.new(abc: 'def')).to eq(abc: 'def')
|
16
|
-
end
|
17
|
-
|
18
|
-
it 'initializes with a hash and a default' do
|
19
|
-
h = subject.new({ abc: 'def' }, 'bar')
|
20
|
-
expect(h[:foo]).to eq 'bar'
|
21
|
-
expect(h[:abc]).to eq 'def'
|
22
|
-
end
|
23
|
-
end
|
@@ -1,121 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Hashie::Extensions::MethodReader do
|
4
|
-
class ReaderHash < Hash
|
5
|
-
include Hashie::Extensions::MethodReader
|
6
|
-
|
7
|
-
def initialize(hash = {})
|
8
|
-
update(hash)
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
subject { ReaderHash }
|
13
|
-
|
14
|
-
it 'reads string keys from the method' do
|
15
|
-
expect(subject.new('awesome' => 'sauce').awesome).to eq 'sauce'
|
16
|
-
end
|
17
|
-
|
18
|
-
it 'reads symbol keys from the method' do
|
19
|
-
expect(subject.new(awesome: 'sauce').awesome).to eq 'sauce'
|
20
|
-
end
|
21
|
-
|
22
|
-
it 'reads nil and false values out properly' do
|
23
|
-
h = subject.new(nil: nil, false: false)
|
24
|
-
expect(h.nil).to eq nil
|
25
|
-
expect(h.false).to eq false
|
26
|
-
end
|
27
|
-
|
28
|
-
it 'raises a NoMethodError for undefined keys' do
|
29
|
-
expect { subject.new.awesome }.to raise_error(NoMethodError)
|
30
|
-
end
|
31
|
-
|
32
|
-
describe '#respond_to?' do
|
33
|
-
it 'is true for string keys' do
|
34
|
-
expect(subject.new('awesome' => 'sauce')).to be_respond_to(:awesome)
|
35
|
-
end
|
36
|
-
|
37
|
-
it 'is true for symbol keys' do
|
38
|
-
expect(subject.new(awesome: 'sauce')).to be_respond_to(:awesome)
|
39
|
-
end
|
40
|
-
|
41
|
-
it 'is false for non-keys' do
|
42
|
-
expect(subject.new).not_to be_respond_to(:awesome)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
describe Hashie::Extensions::MethodWriter do
|
48
|
-
class WriterHash < Hash
|
49
|
-
include Hashie::Extensions::MethodWriter
|
50
|
-
end
|
51
|
-
|
52
|
-
subject { WriterHash.new }
|
53
|
-
|
54
|
-
it 'writes from a method call' do
|
55
|
-
subject.awesome = 'sauce'
|
56
|
-
expect(subject['awesome']).to eq 'sauce'
|
57
|
-
end
|
58
|
-
|
59
|
-
it 'converts the key using the #convert_key method' do
|
60
|
-
allow(subject).to receive(:convert_key).and_return(:awesome)
|
61
|
-
subject.awesome = 'sauce'
|
62
|
-
expect(subject[:awesome]).to eq 'sauce'
|
63
|
-
end
|
64
|
-
|
65
|
-
it 'raises NoMethodError on non equals-ending methods' do
|
66
|
-
expect { subject.awesome }.to raise_error(NoMethodError)
|
67
|
-
end
|
68
|
-
|
69
|
-
it '#respond_to? correctly' do
|
70
|
-
expect(subject).to be_respond_to(:abc=)
|
71
|
-
expect(subject).not_to be_respond_to(:abc)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
describe Hashie::Extensions::MethodQuery do
|
76
|
-
class QueryHash < Hash
|
77
|
-
include Hashie::Extensions::MethodQuery
|
78
|
-
|
79
|
-
def initialize(hash = {})
|
80
|
-
update(hash)
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
subject { QueryHash }
|
85
|
-
|
86
|
-
it 'is true for non-nil string key values' do
|
87
|
-
expect(subject.new('abc' => 123)).to be_abc
|
88
|
-
end
|
89
|
-
|
90
|
-
it 'is true for non-nil symbol key values' do
|
91
|
-
expect(subject.new(abc: 123)).to be_abc
|
92
|
-
end
|
93
|
-
|
94
|
-
it 'is false for nil key values' do
|
95
|
-
expect(subject.new(abc: false)).not_to be_abc
|
96
|
-
end
|
97
|
-
|
98
|
-
it 'raises a NoMethodError for non-set keys' do
|
99
|
-
expect { subject.new.abc? }.to raise_error(NoMethodError)
|
100
|
-
end
|
101
|
-
|
102
|
-
it '#respond_to? for existing string keys' do
|
103
|
-
expect(subject.new('abc' => 'def')).to be_respond_to('abc?')
|
104
|
-
end
|
105
|
-
|
106
|
-
it '#respond_to? for existing symbol keys' do
|
107
|
-
expect(subject.new(abc: 'def')).to be_respond_to(:abc?)
|
108
|
-
end
|
109
|
-
|
110
|
-
it 'does not #respond_to? for non-existent keys' do
|
111
|
-
expect(subject.new).not_to be_respond_to('abc?')
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
describe Hashie::Extensions::MethodAccess do
|
116
|
-
it 'includes all of the other method mixins' do
|
117
|
-
klass = Class.new(Hash)
|
118
|
-
klass.send :include, Hashie::Extensions::MethodAccess
|
119
|
-
expect((klass.ancestors & [Hashie::Extensions::MethodReader, Hashie::Extensions::MethodWriter, Hashie::Extensions::MethodQuery]).size).to eq 3
|
120
|
-
end
|
121
|
-
end
|
data/spec/hashie/hash_spec.rb
DELETED
@@ -1,66 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Hash do
|
4
|
-
it 'is convertible to a Hashie::Mash' do
|
5
|
-
mash = Hashie::Hash[some: 'hash'].to_mash
|
6
|
-
expect(mash.is_a?(Hashie::Mash)).to be true
|
7
|
-
expect(mash.some).to eq 'hash'
|
8
|
-
end
|
9
|
-
|
10
|
-
it '#stringify_keys! turns all keys into strings' do
|
11
|
-
hash = Hashie::Hash[:a => 'hey', 123 => 'bob']
|
12
|
-
hash.stringify_keys!
|
13
|
-
expect(hash).to eq Hashie::Hash['a' => 'hey', '123' => 'bob']
|
14
|
-
end
|
15
|
-
|
16
|
-
it '#stringify_keys returns a hash with stringified keys' do
|
17
|
-
hash = Hashie::Hash[:a => 'hey', 123 => 'bob']
|
18
|
-
stringified_hash = hash.stringify_keys
|
19
|
-
expect(hash).to eq Hashie::Hash[:a => 'hey', 123 => 'bob']
|
20
|
-
expect(stringified_hash).to eq Hashie::Hash['a' => 'hey', '123' => 'bob']
|
21
|
-
end
|
22
|
-
|
23
|
-
it '#to_hash returns a hash with stringified keys' do
|
24
|
-
hash = Hashie::Hash['a' => 'hey', 123 => 'bob', 'array' => [1, 2, 3]]
|
25
|
-
stringified_hash = hash.to_hash
|
26
|
-
expect(stringified_hash).to eq('a' => 'hey', '123' => 'bob', 'array' => [1, 2, 3])
|
27
|
-
end
|
28
|
-
|
29
|
-
it '#to_hash with symbolize_keys set to true returns a hash with symbolized keys' do
|
30
|
-
hash = Hashie::Hash['a' => 'hey', 123 => 'bob', 'array' => [1, 2, 3]]
|
31
|
-
symbolized_hash = hash.to_hash(symbolize_keys: true)
|
32
|
-
expect(symbolized_hash).to eq(:a => 'hey', :"123" => 'bob', :array => [1, 2, 3])
|
33
|
-
end
|
34
|
-
|
35
|
-
it "#to_hash should not blow up when #to_hash doesn't accept arguments" do
|
36
|
-
class BareCustomMash < Hashie::Mash
|
37
|
-
def to_hash
|
38
|
-
{}
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
h = Hashie::Hash.new
|
43
|
-
h[:key] = BareCustomMash.new
|
44
|
-
expect { h.to_hash }.not_to raise_error
|
45
|
-
end
|
46
|
-
|
47
|
-
describe 'when the value is an object that respond_to to_hash' do
|
48
|
-
class ClassRespondsToHash
|
49
|
-
def to_hash(options = {})
|
50
|
-
Hashie::Hash['a' => 'hey', b: 'bar', 123 => 'bob', 'array' => [1, 2, 3]].to_hash(options)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
it '#to_hash with stringify_keys set to true returns a hash with stringified_keys' do
|
55
|
-
hash = Hashie::Hash['a' => 'hey', 123 => 'bob', 'array' => [1, 2, 3], subhash: ClassRespondsToHash.new]
|
56
|
-
symbolized_hash = hash.to_hash(stringify_keys: true)
|
57
|
-
expect(symbolized_hash).to eq('a' => 'hey', '123' => 'bob', 'array' => [1, 2, 3], 'subhash' => { 'a' => 'hey', 'b' => 'bar', '123' => 'bob', 'array' => [1, 2, 3] })
|
58
|
-
end
|
59
|
-
|
60
|
-
it '#to_hash with symbolize_keys set to true returns a hash with symbolized keys' do
|
61
|
-
hash = Hashie::Hash['a' => 'hey', 123 => 'bob', 'array' => [1, 2, 3], subhash: ClassRespondsToHash.new]
|
62
|
-
symbolized_hash = hash.to_hash(symbolize_keys: true)
|
63
|
-
expect(symbolized_hash).to eq(:a => 'hey', :"123" => 'bob', :array => [1, 2, 3], subhash: { :a => 'hey', :b => 'bar', :'123' => 'bob', :array => [1, 2, 3] })
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
data/spec/hashie/mash_spec.rb
DELETED
@@ -1,467 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'delegate'
|
3
|
-
|
4
|
-
describe Hashie::Mash do
|
5
|
-
subject { Hashie::Mash.new }
|
6
|
-
|
7
|
-
it 'inherits from Hash' do
|
8
|
-
expect(subject.is_a?(Hash)).to be true
|
9
|
-
end
|
10
|
-
|
11
|
-
it 'sets hash values through method= calls' do
|
12
|
-
subject.test = 'abc'
|
13
|
-
expect(subject['test']).to eq 'abc'
|
14
|
-
end
|
15
|
-
|
16
|
-
it 'retrieves set values through method calls' do
|
17
|
-
subject['test'] = 'abc'
|
18
|
-
expect(subject.test).to eq 'abc'
|
19
|
-
end
|
20
|
-
|
21
|
-
it 'retrieves set values through blocks' do
|
22
|
-
subject['test'] = 'abc'
|
23
|
-
value = nil
|
24
|
-
subject.[]('test') { |v| value = v }
|
25
|
-
expect(value).to eq 'abc'
|
26
|
-
end
|
27
|
-
|
28
|
-
it 'retrieves set values through blocks with method calls' do
|
29
|
-
subject['test'] = 'abc'
|
30
|
-
value = nil
|
31
|
-
subject.test { |v| value = v }
|
32
|
-
expect(value).to eq 'abc'
|
33
|
-
end
|
34
|
-
|
35
|
-
it 'tests for already set values when passed a ? method' do
|
36
|
-
expect(subject.test?).to be false
|
37
|
-
subject.test = 'abc'
|
38
|
-
expect(subject.test?).to be true
|
39
|
-
end
|
40
|
-
|
41
|
-
it 'returns false on a ? method if a value has been set to nil or false' do
|
42
|
-
subject.test = nil
|
43
|
-
expect(subject).not_to be_test
|
44
|
-
subject.test = false
|
45
|
-
expect(subject).not_to be_test
|
46
|
-
end
|
47
|
-
|
48
|
-
it 'makes all [] and []= into strings for consistency' do
|
49
|
-
subject['abc'] = 123
|
50
|
-
expect(subject.key?('abc')).to be true
|
51
|
-
expect(subject['abc']).to eq 123
|
52
|
-
end
|
53
|
-
|
54
|
-
it 'has a to_s that is identical to its inspect' do
|
55
|
-
subject.abc = 123
|
56
|
-
expect(subject.to_s).to eq subject.inspect
|
57
|
-
end
|
58
|
-
|
59
|
-
it 'returns nil instead of raising an error for attribute-esque method calls' do
|
60
|
-
expect(subject.abc).to be_nil
|
61
|
-
end
|
62
|
-
|
63
|
-
it 'returns the default value if set like Hash' do
|
64
|
-
subject.default = 123
|
65
|
-
expect(subject.abc).to eq 123
|
66
|
-
end
|
67
|
-
|
68
|
-
it 'gracefully handles being accessed with arguments' do
|
69
|
-
expect(subject.abc('foobar')).to eq nil
|
70
|
-
subject.abc = 123
|
71
|
-
expect(subject.abc('foobar')).to eq 123
|
72
|
-
end
|
73
|
-
|
74
|
-
it 'returns a Hashie::Mash when passed a bang method to a non-existenct key' do
|
75
|
-
expect(subject.abc!.is_a?(Hashie::Mash)).to be true
|
76
|
-
end
|
77
|
-
|
78
|
-
it 'returns the existing value when passed a bang method for an existing key' do
|
79
|
-
subject.name = 'Bob'
|
80
|
-
expect(subject.name!).to eq 'Bob'
|
81
|
-
end
|
82
|
-
|
83
|
-
it 'returns a Hashie::Mash when passed an under bang method to a non-existenct key' do
|
84
|
-
expect(subject.abc_.is_a?(Hashie::Mash)).to be true
|
85
|
-
end
|
86
|
-
|
87
|
-
it 'returns the existing value when passed an under bang method for an existing key' do
|
88
|
-
subject.name = 'Bob'
|
89
|
-
expect(subject.name_).to eq 'Bob'
|
90
|
-
end
|
91
|
-
|
92
|
-
it '#initializing_reader returns a Hashie::Mash when passed a non-existent key' do
|
93
|
-
expect(subject.initializing_reader(:abc).is_a?(Hashie::Mash)).to be true
|
94
|
-
end
|
95
|
-
|
96
|
-
it 'allows for multi-level assignment through bang methods' do
|
97
|
-
subject.author!.name = 'Michael Bleigh'
|
98
|
-
expect(subject.author).to eq Hashie::Mash.new(name: 'Michael Bleigh')
|
99
|
-
subject.author!.website!.url = 'http://www.mbleigh.com/'
|
100
|
-
expect(subject.author.website).to eq Hashie::Mash.new(url: 'http://www.mbleigh.com/')
|
101
|
-
end
|
102
|
-
|
103
|
-
it 'allows for multi-level under bang testing' do
|
104
|
-
expect(subject.author_.website_.url).to be_nil
|
105
|
-
expect(subject.author_.website_.url?).to eq false
|
106
|
-
expect(subject.author).to be_nil
|
107
|
-
end
|
108
|
-
|
109
|
-
it 'does not call super if id is not a key' do
|
110
|
-
expect(subject.id).to eq nil
|
111
|
-
end
|
112
|
-
|
113
|
-
it 'returns the value if id is a key' do
|
114
|
-
subject.id = 'Steve'
|
115
|
-
expect(subject.id).to eq 'Steve'
|
116
|
-
end
|
117
|
-
|
118
|
-
it 'does not call super if type is not a key' do
|
119
|
-
expect(subject.type).to eq nil
|
120
|
-
end
|
121
|
-
|
122
|
-
it 'returns the value if type is a key' do
|
123
|
-
subject.type = 'Steve'
|
124
|
-
expect(subject.type).to eq 'Steve'
|
125
|
-
end
|
126
|
-
|
127
|
-
context 'updating' do
|
128
|
-
subject do
|
129
|
-
described_class.new(
|
130
|
-
first_name: 'Michael',
|
131
|
-
last_name: 'Bleigh',
|
132
|
-
details: {
|
133
|
-
email: 'michael@asf.com',
|
134
|
-
address: 'Nowhere road'
|
135
|
-
})
|
136
|
-
end
|
137
|
-
|
138
|
-
describe '#deep_update' do
|
139
|
-
it 'recursively Hashie::Mash Hashie::Mashes and hashes together' do
|
140
|
-
subject.deep_update(details: { email: 'michael@intridea.com', city: 'Imagineton' })
|
141
|
-
expect(subject.first_name).to eq 'Michael'
|
142
|
-
expect(subject.details.email).to eq 'michael@intridea.com'
|
143
|
-
expect(subject.details.address).to eq 'Nowhere road'
|
144
|
-
expect(subject.details.city).to eq 'Imagineton'
|
145
|
-
end
|
146
|
-
|
147
|
-
it 'converts values only once' do
|
148
|
-
class ConvertedMash < Hashie::Mash
|
149
|
-
end
|
150
|
-
|
151
|
-
rhs = ConvertedMash.new(email: 'foo@bar.com')
|
152
|
-
expect(subject).to receive(:convert_value).exactly(1).times
|
153
|
-
subject.deep_update(rhs)
|
154
|
-
end
|
155
|
-
|
156
|
-
it 'makes #update deep by default' do
|
157
|
-
expect(subject.update(details: { address: 'Fake street' })).to eql(subject)
|
158
|
-
expect(subject.details.address).to eq 'Fake street'
|
159
|
-
expect(subject.details.email).to eq 'michael@asf.com'
|
160
|
-
end
|
161
|
-
|
162
|
-
it 'clones before a #deep_merge' do
|
163
|
-
duped = subject.deep_merge(details: { address: 'Fake street' })
|
164
|
-
expect(duped).not_to eql(subject)
|
165
|
-
expect(duped.details.address).to eq 'Fake street'
|
166
|
-
expect(subject.details.address).to eq 'Nowhere road'
|
167
|
-
expect(duped.details.email).to eq 'michael@asf.com'
|
168
|
-
end
|
169
|
-
|
170
|
-
it 'default #merge is deep' do
|
171
|
-
duped = subject.merge(details: { email: 'michael@intridea.com' })
|
172
|
-
expect(duped).not_to eql(subject)
|
173
|
-
expect(duped.details.email).to eq 'michael@intridea.com'
|
174
|
-
expect(duped.details.address).to eq 'Nowhere road'
|
175
|
-
end
|
176
|
-
|
177
|
-
# http://www.ruby-doc.org/core-1.9.3/Hash.html#method-i-update
|
178
|
-
it 'accepts a block' do
|
179
|
-
duped = subject.merge(details: { address: 'Pasadena CA' }) { |key, oldv, newv| [oldv, newv].join(', ') }
|
180
|
-
expect(duped.details.address).to eq 'Nowhere road, Pasadena CA'
|
181
|
-
end
|
182
|
-
end
|
183
|
-
|
184
|
-
describe 'shallow update' do
|
185
|
-
it 'shallowly Hashie::Mash Hashie::Mashes and hashes together' do
|
186
|
-
expect(subject.shallow_update(details: { email: 'michael@intridea.com',
|
187
|
-
city: 'Imagineton' })).to eql(subject)
|
188
|
-
|
189
|
-
expect(subject.first_name).to eq 'Michael'
|
190
|
-
expect(subject.details.email).to eq 'michael@intridea.com'
|
191
|
-
expect(subject.details.address).to be_nil
|
192
|
-
expect(subject.details.city).to eq 'Imagineton'
|
193
|
-
end
|
194
|
-
|
195
|
-
it 'clones before a #regular_merge' do
|
196
|
-
duped = subject.shallow_merge(details: { address: 'Fake street' })
|
197
|
-
expect(duped).not_to eql(subject)
|
198
|
-
end
|
199
|
-
|
200
|
-
it 'default #merge is shallow' do
|
201
|
-
duped = subject.shallow_merge(details: { address: 'Fake street' })
|
202
|
-
expect(duped.details.address).to eq 'Fake street'
|
203
|
-
expect(subject.details.address).to eq 'Nowhere road'
|
204
|
-
expect(duped.details.email).to be_nil
|
205
|
-
end
|
206
|
-
end
|
207
|
-
|
208
|
-
describe '#replace' do
|
209
|
-
before do
|
210
|
-
subject.replace(
|
211
|
-
middle_name: 'Cain',
|
212
|
-
details: { city: 'Imagination' }
|
213
|
-
)
|
214
|
-
end
|
215
|
-
|
216
|
-
it 'returns self' do
|
217
|
-
expect(subject.replace(foo: 'bar').to_hash).to eq('foo' => 'bar')
|
218
|
-
end
|
219
|
-
|
220
|
-
it 'sets all specified keys to their corresponding values' do
|
221
|
-
expect(subject.middle_name?).to be true
|
222
|
-
expect(subject.details?).to be true
|
223
|
-
expect(subject.middle_name).to eq 'Cain'
|
224
|
-
expect(subject.details.city?).to be true
|
225
|
-
expect(subject.details.city).to eq 'Imagination'
|
226
|
-
end
|
227
|
-
|
228
|
-
it 'leaves only specified keys' do
|
229
|
-
expect(subject.keys.sort).to eq %w(details middle_name)
|
230
|
-
expect(subject.first_name?).to be false
|
231
|
-
expect(subject).not_to respond_to(:first_name)
|
232
|
-
expect(subject.last_name?).to be false
|
233
|
-
expect(subject).not_to respond_to(:last_name)
|
234
|
-
end
|
235
|
-
end
|
236
|
-
|
237
|
-
describe 'delete' do
|
238
|
-
it 'deletes with String key' do
|
239
|
-
subject.delete('details')
|
240
|
-
expect(subject.details).to be_nil
|
241
|
-
expect(subject).not_to be_respond_to :details
|
242
|
-
end
|
243
|
-
|
244
|
-
it 'deletes with Symbol key' do
|
245
|
-
subject.delete(:details)
|
246
|
-
expect(subject.details).to be_nil
|
247
|
-
expect(subject).not_to be_respond_to :details
|
248
|
-
end
|
249
|
-
end
|
250
|
-
end
|
251
|
-
|
252
|
-
it 'converts hash assignments into Hashie::Mashes' do
|
253
|
-
subject.details = { email: 'randy@asf.com', address: { state: 'TX' } }
|
254
|
-
expect(subject.details.email).to eq 'randy@asf.com'
|
255
|
-
expect(subject.details.address.state).to eq 'TX'
|
256
|
-
end
|
257
|
-
|
258
|
-
it 'does not convert the type of Hashie::Mashes childs to Hashie::Mash' do
|
259
|
-
class MyMash < Hashie::Mash
|
260
|
-
end
|
261
|
-
|
262
|
-
record = MyMash.new
|
263
|
-
record.son = MyMash.new
|
264
|
-
expect(record.son.class).to eq MyMash
|
265
|
-
end
|
266
|
-
|
267
|
-
it 'does not change the class of Mashes when converted' do
|
268
|
-
class SubMash < Hashie::Mash
|
269
|
-
end
|
270
|
-
|
271
|
-
record = Hashie::Mash.new
|
272
|
-
son = SubMash.new
|
273
|
-
record['submash'] = son
|
274
|
-
expect(record['submash']).to be_kind_of(SubMash)
|
275
|
-
end
|
276
|
-
|
277
|
-
it 'respects the class when passed a bang method for a non-existent key' do
|
278
|
-
record = Hashie::Mash.new
|
279
|
-
expect(record.non_existent!).to be_kind_of(Hashie::Mash)
|
280
|
-
|
281
|
-
class SubMash < Hashie::Mash
|
282
|
-
end
|
283
|
-
|
284
|
-
son = SubMash.new
|
285
|
-
expect(son.non_existent!).to be_kind_of(SubMash)
|
286
|
-
end
|
287
|
-
|
288
|
-
it 'respects the class when passed an under bang method for a non-existent key' do
|
289
|
-
record = Hashie::Mash.new
|
290
|
-
expect(record.non_existent_).to be_kind_of(Hashie::Mash)
|
291
|
-
|
292
|
-
class SubMash < Hashie::Mash
|
293
|
-
end
|
294
|
-
|
295
|
-
son = SubMash.new
|
296
|
-
expect(son.non_existent_).to be_kind_of(SubMash)
|
297
|
-
end
|
298
|
-
|
299
|
-
it 'respects the class when converting the value' do
|
300
|
-
record = Hashie::Mash.new
|
301
|
-
record.details = Hashie::Mash.new(email: 'randy@asf.com')
|
302
|
-
expect(record.details).to be_kind_of(Hashie::Mash)
|
303
|
-
end
|
304
|
-
|
305
|
-
it 'respects another subclass when converting the value' do
|
306
|
-
record = Hashie::Mash.new
|
307
|
-
|
308
|
-
class SubMash < Hashie::Mash
|
309
|
-
end
|
310
|
-
|
311
|
-
son = SubMash.new(email: 'foo@bar.com')
|
312
|
-
record.details = son
|
313
|
-
expect(record.details).to be_kind_of(SubMash)
|
314
|
-
end
|
315
|
-
|
316
|
-
describe '#respond_to?' do
|
317
|
-
it 'responds to a normal method' do
|
318
|
-
expect(Hashie::Mash.new).to be_respond_to(:key?)
|
319
|
-
end
|
320
|
-
|
321
|
-
it 'responds to a set key' do
|
322
|
-
expect(Hashie::Mash.new(abc: 'def')).to be_respond_to(:abc)
|
323
|
-
end
|
324
|
-
|
325
|
-
it 'responds to a set key with a suffix' do
|
326
|
-
%w(= ? ! _).each do |suffix|
|
327
|
-
expect(Hashie::Mash.new(abc: 'def')).to be_respond_to(:"abc#{suffix}")
|
328
|
-
end
|
329
|
-
end
|
330
|
-
|
331
|
-
it 'does not respond to an unknown key with a suffix' do
|
332
|
-
%w(= ? ! _).each do |suffix|
|
333
|
-
expect(Hashie::Mash.new(abc: 'def')).not_to be_respond_to(:"xyz#{suffix}")
|
334
|
-
end
|
335
|
-
end
|
336
|
-
|
337
|
-
it 'does not respond to an unknown key without a suffix' do
|
338
|
-
expect(Hashie::Mash.new(abc: 'def')).not_to be_respond_to(:xyz)
|
339
|
-
end
|
340
|
-
|
341
|
-
it 'does not respond to permitted?' do
|
342
|
-
expect(Hashie::Mash.new).not_to be_respond_to(:permitted?)
|
343
|
-
end
|
344
|
-
end
|
345
|
-
|
346
|
-
context '#initialize' do
|
347
|
-
it 'converts an existing hash to a Hashie::Mash' do
|
348
|
-
converted = Hashie::Mash.new(abc: 123, name: 'Bob')
|
349
|
-
expect(converted.abc).to eq 123
|
350
|
-
expect(converted.name).to eq 'Bob'
|
351
|
-
end
|
352
|
-
|
353
|
-
it 'converts hashes recursively into Hashie::Mashes' do
|
354
|
-
converted = Hashie::Mash.new(a: { b: 1, c: { d: 23 } })
|
355
|
-
expect(converted.a.is_a?(Hashie::Mash)).to be true
|
356
|
-
expect(converted.a.b).to eq 1
|
357
|
-
expect(converted.a.c.d).to eq 23
|
358
|
-
end
|
359
|
-
|
360
|
-
it 'converts hashes in arrays into Hashie::Mashes' do
|
361
|
-
converted = Hashie::Mash.new(a: [{ b: 12 }, 23])
|
362
|
-
expect(converted.a.first.b).to eq 12
|
363
|
-
expect(converted.a.last).to eq 23
|
364
|
-
end
|
365
|
-
|
366
|
-
it 'converts an existing Hashie::Mash into a Hashie::Mash' do
|
367
|
-
initial = Hashie::Mash.new(name: 'randy', address: { state: 'TX' })
|
368
|
-
copy = Hashie::Mash.new(initial)
|
369
|
-
expect(initial.name).to eq copy.name
|
370
|
-
expect(initial.__id__).not_to eq copy.__id__
|
371
|
-
expect(copy.address.state).to eq 'TX'
|
372
|
-
copy.address.state = 'MI'
|
373
|
-
expect(initial.address.state).to eq 'TX'
|
374
|
-
expect(copy.address.__id__).not_to eq initial.address.__id__
|
375
|
-
end
|
376
|
-
|
377
|
-
it 'accepts a default block' do
|
378
|
-
initial = Hashie::Mash.new { |h, i| h[i] = [] }
|
379
|
-
expect(initial.default_proc).not_to be_nil
|
380
|
-
expect(initial.default).to be_nil
|
381
|
-
expect(initial.test).to eq []
|
382
|
-
expect(initial.test?).to be true
|
383
|
-
end
|
384
|
-
|
385
|
-
it 'converts Hashie::Mashes within Arrays back to Hashes' do
|
386
|
-
initial_hash = { 'a' => [{ 'b' => 12, 'c' => ['d' => 50, 'e' => 51] }, 23] }
|
387
|
-
converted = Hashie::Mash.new(initial_hash)
|
388
|
-
expect(converted.to_hash['a'].first.is_a?(Hashie::Mash)).to be false
|
389
|
-
expect(converted.to_hash['a'].first.is_a?(Hash)).to be true
|
390
|
-
expect(converted.to_hash['a'].first['c'].first.is_a?(Hashie::Mash)).to be false
|
391
|
-
end
|
392
|
-
end
|
393
|
-
|
394
|
-
describe '#fetch' do
|
395
|
-
let(:hash) { { one: 1, other: false } }
|
396
|
-
let(:mash) { Hashie::Mash.new(hash) }
|
397
|
-
|
398
|
-
context 'when key exists' do
|
399
|
-
it 'returns the value' do
|
400
|
-
expect(mash.fetch(:one)).to eql(1)
|
401
|
-
end
|
402
|
-
|
403
|
-
it 'returns the value even if the value is falsy' do
|
404
|
-
expect(mash.fetch(:other)).to eql(false)
|
405
|
-
end
|
406
|
-
|
407
|
-
context 'when key has other than original but acceptable type' do
|
408
|
-
it 'returns the value' do
|
409
|
-
expect(mash.fetch('one')).to eql(1)
|
410
|
-
end
|
411
|
-
end
|
412
|
-
end
|
413
|
-
|
414
|
-
context 'when key does not exist' do
|
415
|
-
it 'raises KeyError' do
|
416
|
-
error = RUBY_VERSION =~ /1.8/ ? IndexError : KeyError
|
417
|
-
expect { mash.fetch(:two) }.to raise_error(error)
|
418
|
-
end
|
419
|
-
|
420
|
-
context 'with default value given' do
|
421
|
-
it 'returns default value' do
|
422
|
-
expect(mash.fetch(:two, 8)).to eql(8)
|
423
|
-
end
|
424
|
-
|
425
|
-
it 'returns default value even if it is falsy' do
|
426
|
-
expect(mash.fetch(:two, false)).to eql(false)
|
427
|
-
end
|
428
|
-
end
|
429
|
-
|
430
|
-
context 'with block given' do
|
431
|
-
it 'returns default value' do
|
432
|
-
expect(mash.fetch(:two) do |key|
|
433
|
-
'block default value'
|
434
|
-
end).to eql('block default value')
|
435
|
-
end
|
436
|
-
end
|
437
|
-
end
|
438
|
-
end
|
439
|
-
|
440
|
-
describe '#to_hash' do
|
441
|
-
let(:hash) { { 'outer' => { 'inner' => 42 }, 'testing' => [1, 2, 3] } }
|
442
|
-
let(:mash) { Hashie::Mash.new(hash) }
|
443
|
-
|
444
|
-
it 'returns a standard Hash' do
|
445
|
-
expect(mash.to_hash).to be_a(::Hash)
|
446
|
-
end
|
447
|
-
|
448
|
-
it 'includes all keys' do
|
449
|
-
expect(mash.to_hash.keys).to eql(%w(outer testing))
|
450
|
-
end
|
451
|
-
|
452
|
-
it 'converts keys to symbols when symbolize_keys option is true' do
|
453
|
-
expect(mash.to_hash(symbolize_keys: true).keys).to include(:outer)
|
454
|
-
expect(mash.to_hash(symbolize_keys: true).keys).not_to include('outer')
|
455
|
-
end
|
456
|
-
|
457
|
-
it 'leaves keys as strings when symbolize_keys option is false' do
|
458
|
-
expect(mash.to_hash(symbolize_keys: false).keys).to include('outer')
|
459
|
-
expect(mash.to_hash(symbolize_keys: false).keys).not_to include(:outer)
|
460
|
-
end
|
461
|
-
|
462
|
-
it 'symbolizes keys recursively' do
|
463
|
-
expect(mash.to_hash(symbolize_keys: true)[:outer].keys).to include(:inner)
|
464
|
-
expect(mash.to_hash(symbolize_keys: true)[:outer].keys).not_to include('inner')
|
465
|
-
end
|
466
|
-
end
|
467
|
-
end
|