dottie 0.0.1
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/.gitignore +17 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +22 -0
- data/README.md +289 -0
- data/Rakefile +8 -0
- data/dottie.gemspec +26 -0
- data/lib/dottie.rb +153 -0
- data/lib/dottie/ext.rb +3 -0
- data/lib/dottie/ext/array.rb +17 -0
- data/lib/dottie/ext/hash.rb +17 -0
- data/lib/dottie/freckle.rb +49 -0
- data/lib/dottie/helper.rb +6 -0
- data/lib/dottie/methods.rb +76 -0
- data/lib/dottie/version.rb +3 -0
- data/spec/array_spec.rb +55 -0
- data/spec/dottie_spec.rb +434 -0
- data/spec/freckle_spec.rb +274 -0
- data/spec/hash_spec.rb +55 -0
- data/spec/spec_helper.rb +1 -0
- metadata +114 -0
@@ -0,0 +1,274 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Dottie::Freckle do
|
4
|
+
|
5
|
+
describe 'general' do
|
6
|
+
|
7
|
+
context 'Hash' do
|
8
|
+
let(:freckle) { Dottie::Freckle.new({ 'a' => 'b' }) }
|
9
|
+
|
10
|
+
it 'makes the original Hash accessible' do
|
11
|
+
expect(freckle.hash).to eq({ 'a' => 'b' })
|
12
|
+
end
|
13
|
+
it 'makes the original Hash accessible' do
|
14
|
+
expect(freckle.wrapped_object).to eq({ 'a' => 'b' })
|
15
|
+
end
|
16
|
+
it 'raises an error if the wrong type is requested' do
|
17
|
+
expect{ freckle.array }.to raise_error TypeError
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'Array' do
|
22
|
+
let(:freckle) { Dottie::Freckle.new([1, 2]) }
|
23
|
+
|
24
|
+
it 'makes the original Array accessible' do
|
25
|
+
expect(freckle.array).to eq([1, 2])
|
26
|
+
end
|
27
|
+
it 'makes the original Array accessible' do
|
28
|
+
expect(freckle.wrapped_object).to eq([1, 2])
|
29
|
+
end
|
30
|
+
it 'raises an error if the wrong type is requested' do
|
31
|
+
expect{ freckle.hash }.to raise_error TypeError
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
describe 'reading' do
|
38
|
+
|
39
|
+
context 'simple' do
|
40
|
+
let(:freckle) { Dottie::Freckle.new({ 'a' => 'b', 'c' => { 'd' => 'e' } }) }
|
41
|
+
|
42
|
+
it 'reads a standard key' do
|
43
|
+
expect(freckle['a']).to eq 'b'
|
44
|
+
end
|
45
|
+
it 'returns nil for a missing standard key' do
|
46
|
+
expect(freckle['d']).to be_nil
|
47
|
+
end
|
48
|
+
it 'reads a dotted key' do
|
49
|
+
expect(freckle['c.d']).to eq 'e'
|
50
|
+
end
|
51
|
+
it 'returns nil for a missing dotted key' do
|
52
|
+
expect(freckle['c.e']).to be_nil
|
53
|
+
end
|
54
|
+
it 'returns nil for a missing nested dotted key' do
|
55
|
+
expect(freckle['c.e.g.x.y']).to be_nil
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'ending array indexes' do
|
60
|
+
let(:freckle) { Dottie::Freckle.new({ 'a' => 'b', 'c' => %w( d e f ) }) }
|
61
|
+
|
62
|
+
it 'reads an integer key' do
|
63
|
+
expect(freckle['c[0]']).to eq 'd'
|
64
|
+
end
|
65
|
+
it 'reads a negative integer key' do
|
66
|
+
expect(freckle['c[-1]']).to eq 'f'
|
67
|
+
end
|
68
|
+
it 'reads a named key (first)' do
|
69
|
+
expect(freckle['c[first]']).to eq 'd'
|
70
|
+
end
|
71
|
+
it 'reads a named key (last)' do
|
72
|
+
expect(freckle['c[last]']).to eq 'f'
|
73
|
+
end
|
74
|
+
it 'returns nil for a missing index' do
|
75
|
+
expect(freckle['c[4]']).to be_nil
|
76
|
+
end
|
77
|
+
it 'returns nil for a missing array' do
|
78
|
+
expect(freckle['x[4]']).to be_nil
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context 'middle array indexes' do
|
83
|
+
let(:freckle) { Dottie::Freckle.new({ 'a' => 'b', 'c' => [{ 'd' => 'e' }, { 'f' => 'g' }] }) }
|
84
|
+
|
85
|
+
it 'reads an integer key' do
|
86
|
+
expect(freckle['c[0].d']).to eq 'e'
|
87
|
+
end
|
88
|
+
it 'reads a negative integer key' do
|
89
|
+
expect(freckle['c[-1].f']).to eq 'g'
|
90
|
+
end
|
91
|
+
it 'reads a named key (first)' do
|
92
|
+
expect(freckle['c[first].d']).to eq 'e'
|
93
|
+
end
|
94
|
+
it 'reads a named key (last)' do
|
95
|
+
expect(freckle['c[last].f']).to eq 'g'
|
96
|
+
end
|
97
|
+
it 'returns nil for a missing index' do
|
98
|
+
expect(freckle['c[4].r']).to be_nil
|
99
|
+
end
|
100
|
+
it 'returns nil for a missing array' do
|
101
|
+
expect(freckle['x[4].s']).to be_nil
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
context 'consecutive array indexes' do
|
106
|
+
let(:freckle) { Dottie::Freckle.new({ 'a' => 'b', 'c' => [ [{}, { 'd' => 'e' }] ] }) }
|
107
|
+
|
108
|
+
it 'reads an integer key' do
|
109
|
+
expect(freckle['c[0][1].d']).to eq 'e'
|
110
|
+
end
|
111
|
+
it 'reads a negative integer key' do
|
112
|
+
expect(freckle['c[-1][1].d']).to eq 'e'
|
113
|
+
end
|
114
|
+
it 'reads a named key (first)' do
|
115
|
+
expect(freckle['c[first][last].d']).to eq 'e'
|
116
|
+
end
|
117
|
+
it 'reads a named key (last)' do
|
118
|
+
expect(freckle['c[last][last].d']).to eq 'e'
|
119
|
+
end
|
120
|
+
it 'returns nil for a missing index' do
|
121
|
+
expect(freckle['c[4][5]']).to be_nil
|
122
|
+
end
|
123
|
+
it 'returns nil for a missing array' do
|
124
|
+
expect(freckle['x[4][5]']).to be_nil
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
|
130
|
+
describe 'key existence' do
|
131
|
+
let(:freckle) { Dottie::Freckle.new({ 'a' => 'b', 'c' => { 'd' => ['e', 'f', 'g'] } }) }
|
132
|
+
|
133
|
+
it "finds a standard key" do
|
134
|
+
expect(freckle.has_key?('a')).to be_true
|
135
|
+
end
|
136
|
+
it "does not find a missing standard key" do
|
137
|
+
expect(freckle.has_key?('x')).to be_false
|
138
|
+
end
|
139
|
+
it "finds a Dottie key (Hash value)" do
|
140
|
+
expect(freckle.has_key?('c.d')).to be_true
|
141
|
+
end
|
142
|
+
it "finds a Dottie key (Array element)" do
|
143
|
+
expect(freckle.has_key?('c.d[0]')).to be_true
|
144
|
+
end
|
145
|
+
it "does not find a missing Dottie key (first part is a String)" do
|
146
|
+
expect(freckle.has_key?('a.b')).to be_false
|
147
|
+
end
|
148
|
+
it "does not find a missing Dottie key (first part exists)" do
|
149
|
+
expect(freckle.has_key?('c.x')).to be_false
|
150
|
+
end
|
151
|
+
it "does not find a missing Dottie key (outside Array bounds)" do
|
152
|
+
expect(freckle.has_key?('c.d[4]')).to be_false
|
153
|
+
end
|
154
|
+
it "does not find a missing Dottie key (no part exists)" do
|
155
|
+
expect(freckle.has_key?('x.y')).to be_false
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
describe 'fetching' do
|
160
|
+
let(:freckle) { Dottie::Freckle.new({ 'a' => 'b', 'c' => { 'd' => ['e', 'f', 'g'] } }) }
|
161
|
+
|
162
|
+
context 'no default' do
|
163
|
+
it 'fetches a standard key' do
|
164
|
+
expect(freckle.fetch('a')).to eq 'b'
|
165
|
+
end
|
166
|
+
it 'fetches a Dottie key (Hash value)' do
|
167
|
+
expect(freckle.fetch('c.d')).to eq ['e', 'f', 'g']
|
168
|
+
end
|
169
|
+
it 'fetches a Dottie key (Array element)' do
|
170
|
+
expect(freckle.fetch('c.d[1]')).to eq 'f'
|
171
|
+
end
|
172
|
+
it 'raises on a missing standard key' do
|
173
|
+
expect{ freckle.fetch('x') }.to raise_error KeyError
|
174
|
+
end
|
175
|
+
it 'raises on a missing Dottie key' do
|
176
|
+
expect{ freckle.fetch('x.y') }.to raise_error KeyError
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
context 'with default' do
|
181
|
+
it 'fetches a standard key' do
|
182
|
+
expect(freckle.fetch('a', 'z')).to eq 'b'
|
183
|
+
end
|
184
|
+
it 'fetches a Dottie key' do
|
185
|
+
expect(freckle.fetch('c.d', 'z')).to eq ['e', 'f', 'g']
|
186
|
+
end
|
187
|
+
it 'returns a default for a missing standard key' do
|
188
|
+
expect(freckle.fetch('x', 'z')).to eq 'z'
|
189
|
+
end
|
190
|
+
it 'returns a default for a missing Dottie key' do
|
191
|
+
expect(freckle.fetch('x', 'z')).to eq 'z'
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
context 'with block' do
|
196
|
+
it 'fetches a standard key' do
|
197
|
+
expect(freckle.fetch('a'){ |key| key.upcase }).to eq 'b'
|
198
|
+
end
|
199
|
+
it 'fetches a Dottie key' do
|
200
|
+
expect(freckle.fetch('c.d'){ |key| key.upcase }).to eq ['e', 'f', 'g']
|
201
|
+
end
|
202
|
+
it 'yields to a block for a missing standard key' do
|
203
|
+
expect(freckle.fetch('x'){ |key| key.upcase }).to eq 'X'
|
204
|
+
end
|
205
|
+
it 'yields to a block for a missing Dottie key' do
|
206
|
+
expect(freckle.fetch('x.y'){ |key| key.upcase }).to eq 'X.Y'
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
end
|
211
|
+
|
212
|
+
describe 'writing' do
|
213
|
+
|
214
|
+
context 'simple' do
|
215
|
+
before :each do
|
216
|
+
@freckle = Dottie::Freckle.new({ 'a' => 'b', 'c' => { 'd' => 'e' } })
|
217
|
+
end
|
218
|
+
|
219
|
+
it 'overwrites a standard key' do
|
220
|
+
@freckle['a'] = 'x'
|
221
|
+
expect(@freckle.hash).to eq({ 'a' => 'x', 'c' => { 'd' => 'e' } })
|
222
|
+
end
|
223
|
+
it 'creates a hash at a non-existent standard key' do
|
224
|
+
@freckle['y'] = 'z'
|
225
|
+
expect(@freckle.hash).to eq({ 'a' => 'b', 'c' => { 'd' => 'e' }, 'y' => 'z' })
|
226
|
+
end
|
227
|
+
it 'overwrites a dotted key' do
|
228
|
+
@freckle['c.d'] = 'm'
|
229
|
+
expect(@freckle.hash).to eq({ 'a' => 'b', 'c' => { 'd' => 'm' } })
|
230
|
+
end
|
231
|
+
it 'creates a hash at a non-existent dotted key' do
|
232
|
+
@freckle['n.o'] = 'p'
|
233
|
+
expect(@freckle.hash).to eq({ 'a' => 'b', 'c' => { 'd' => 'e' }, 'n' => { 'o' => 'p' } })
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
context 'array indexes' do
|
238
|
+
before :each do
|
239
|
+
@freckle = Dottie::Freckle.new({ 'a' => 'b', 'c' => %w( d e f ) })
|
240
|
+
end
|
241
|
+
|
242
|
+
it 'overwrites an array element (positive index)' do
|
243
|
+
@freckle['c[0]'] = 'x'
|
244
|
+
expect(@freckle.hash).to eq({ 'a' => 'b', 'c' => ['x', 'e', 'f'] })
|
245
|
+
end
|
246
|
+
it 'overwrites an array element (negative index)' do
|
247
|
+
@freckle['c[-2]'] = 'y'
|
248
|
+
expect(@freckle.hash).to eq({ 'a' => 'b', 'c' => ['d', 'y', 'f'] })
|
249
|
+
end
|
250
|
+
it 'overwrites an array element ("first")' do
|
251
|
+
@freckle['c[first]'] = 'm'
|
252
|
+
expect(@freckle.hash).to eq({ 'a' => 'b', 'c' => ['m', 'e', 'f'] })
|
253
|
+
end
|
254
|
+
it 'overwrites an array element ("last")' do
|
255
|
+
@freckle['c[last]'] = 'n'
|
256
|
+
expect(@freckle.hash).to eq({ 'a' => 'b', 'c' => ['d', 'e', 'n'] })
|
257
|
+
end
|
258
|
+
it 'creates an array at a non-existent key (positive index)' do
|
259
|
+
@freckle['r[0]'] = 's'
|
260
|
+
expect(@freckle.hash).to eq({ 'a' => 'b', 'c' => ['d', 'e', 'f'], 'r' => ['s'] })
|
261
|
+
end
|
262
|
+
it 'creates an array at a non-existent key ("first")' do
|
263
|
+
@freckle['r[first]'] = 's'
|
264
|
+
expect(@freckle.hash).to eq({ 'a' => 'b', 'c' => ['d', 'e', 'f'], 'r' => ['s'] })
|
265
|
+
end
|
266
|
+
it 'adds an array element' do
|
267
|
+
@freckle['c[3]'] = 'g'
|
268
|
+
expect(@freckle.hash).to eq({ 'a' => 'b', 'c' => ['d', 'e', 'f', 'g'] })
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
end
|
273
|
+
|
274
|
+
end
|
data/spec/hash_spec.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'dottie/ext'
|
3
|
+
|
4
|
+
describe Hash do
|
5
|
+
|
6
|
+
describe 'Dottie extensions' do
|
7
|
+
before :each do
|
8
|
+
@hash = { 'a' => 'b', 'c' => { 'd' => 'e' } }
|
9
|
+
end
|
10
|
+
|
11
|
+
context 'untouched' do
|
12
|
+
it "should not have Dottie's behavior" do
|
13
|
+
expect(@hash['a.b']).to be_nil
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'wrapped' do
|
18
|
+
let(:freckle) { @hash.dottie }
|
19
|
+
|
20
|
+
it 'is no longer a Hash' do
|
21
|
+
expect(freckle).to_not be_a Hash
|
22
|
+
end
|
23
|
+
it 'wraps a Hash in a Dottie::Freckle' do
|
24
|
+
expect(freckle).to be_a Dottie::Freckle
|
25
|
+
end
|
26
|
+
it 'acts like a regular Hash for standard keys' do
|
27
|
+
expect(freckle['a']).to eq 'b'
|
28
|
+
end
|
29
|
+
it "has Dottie's behavior" do
|
30
|
+
expect(freckle['c.d']).to eq 'e'
|
31
|
+
end
|
32
|
+
it "does not add Dottie's behavior to the original Hash" do
|
33
|
+
expect(@hash['a.b']).to be_nil
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'mixed in' do
|
38
|
+
before :each do
|
39
|
+
@hash.dottie!
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'is still a Hash' do
|
43
|
+
expect(@hash).to be_a Hash
|
44
|
+
end
|
45
|
+
it 'acts like a regular Hash for standard keys' do
|
46
|
+
expect(@hash['a']).to eq 'b'
|
47
|
+
end
|
48
|
+
it "adds Dottie's behavior to a Hash" do
|
49
|
+
expect(@hash['c.d']).to eq 'e'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'dottie'
|
metadata
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dottie
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nick Pearson
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-05-08 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.5'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.5'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: |-
|
56
|
+
Deeply access nested Hash/Array data structures
|
57
|
+
without checking for the existence of every node
|
58
|
+
along the way.
|
59
|
+
email:
|
60
|
+
- nick@banyantheory.com
|
61
|
+
executables: []
|
62
|
+
extensions: []
|
63
|
+
extra_rdoc_files: []
|
64
|
+
files:
|
65
|
+
- ".gitignore"
|
66
|
+
- Gemfile
|
67
|
+
- LICENSE.txt
|
68
|
+
- README.md
|
69
|
+
- Rakefile
|
70
|
+
- dottie.gemspec
|
71
|
+
- lib/dottie.rb
|
72
|
+
- lib/dottie/ext.rb
|
73
|
+
- lib/dottie/ext/array.rb
|
74
|
+
- lib/dottie/ext/hash.rb
|
75
|
+
- lib/dottie/freckle.rb
|
76
|
+
- lib/dottie/helper.rb
|
77
|
+
- lib/dottie/methods.rb
|
78
|
+
- lib/dottie/version.rb
|
79
|
+
- spec/array_spec.rb
|
80
|
+
- spec/dottie_spec.rb
|
81
|
+
- spec/freckle_spec.rb
|
82
|
+
- spec/hash_spec.rb
|
83
|
+
- spec/spec_helper.rb
|
84
|
+
homepage: https://github.com/nickpearson/dottie
|
85
|
+
licenses:
|
86
|
+
- MIT
|
87
|
+
metadata: {}
|
88
|
+
post_install_message:
|
89
|
+
rdoc_options: []
|
90
|
+
require_paths:
|
91
|
+
- lib
|
92
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
requirements: []
|
103
|
+
rubyforge_project:
|
104
|
+
rubygems_version: 2.2.2
|
105
|
+
signing_key:
|
106
|
+
specification_version: 4
|
107
|
+
summary: Deep Hash and Array access with dotted keys
|
108
|
+
test_files:
|
109
|
+
- spec/array_spec.rb
|
110
|
+
- spec/dottie_spec.rb
|
111
|
+
- spec/freckle_spec.rb
|
112
|
+
- spec/hash_spec.rb
|
113
|
+
- spec/spec_helper.rb
|
114
|
+
has_rdoc:
|