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