dottie 0.0.1 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: a050415bffe078f5aa5be713416cfb686a9ec913
4
- data.tar.gz: 6f9af95ef6a28fbd9a07ae1fdc3b519c9c4a77d9
2
+ SHA256:
3
+ metadata.gz: 56422c24e86966e8928fdd65ae47c56527a1ac72c75d0d6ff7674fa6c467088b
4
+ data.tar.gz: 815ece0b81778ef2ab9a66dbe8e467fffc1500a73ca7f30e2d13957d51ad83fe
5
5
  SHA512:
6
- metadata.gz: 46a17f46eb85e0757d222f1e1c2e81ab6e1cccc4657d5e6f723a091edf69013c6553b0b3cfe8e37409bd0c43a46eef739a8f85a7ce4c3f5a2241dea843e9b744
7
- data.tar.gz: 06f2654c46e34627a7de943f59c9f2209413a5f3306733a4e34ebdfdbfc7322f89e780610a34ee890893770c23652cc4697cb5390f0be58536eb9f18025b8ff2
6
+ metadata.gz: '0878011a1e5a80b62a8aedcc81b48da2777768d5d2011829e4669db535c2999e6c2b41ab668bbfe7d209d35e123bcd669ee434c377c3344924ff462c6d349eca'
7
+ data.tar.gz: f371ca692a797e919b6f4ad89cd205365d4e06e8f1d422ce753221d151524ee9a4637c7ef9e63e77d5562618307b71cc31ed891b3ab82e1f4341fee59b08c20b
data/README.md CHANGED
@@ -115,6 +115,21 @@ complex.hash # => {"a"=>[{"b"=>"x"}, {"d"=>"e"}]}
115
115
  # add another array element
116
116
  complex['a[2]'] = 'y'
117
117
  complex.hash # => {"a"=>[{"b"=>"x"}, {"d"=>"e"}, "y"]}
118
+
119
+ # elements can also be prepended and appended to arrays
120
+ complex['a[+]'] = 'z' # can also use 'a[<<]' and 'a[append]'
121
+ complex.hash # => {"a"=>[{"b"=>"x"}, {"d"=>"e"}, "y", "z"]}
122
+
123
+ complex['a[-]'] = 'p' # can also use 'a[>>]' and 'a[prepend]'
124
+ complex.hash # => {"a"=>["p", {"b"=>"x"}, {"d"=>"e"}, "y", "z"]}
125
+
126
+ # use delete as you would on a Hash
127
+ complex.delete('a[1].b') # => "x"
128
+ complex.hash # => {"a"=>["p", {}, {"d"=>"e"}, "y", "z"]}
129
+
130
+ # delete an element at an array index
131
+ complex.delete('a[1]') # => {}
132
+ complex.hash # => {"a"=>["p", {"d"=>"e"}, "y", "z"]}
118
133
  ```
119
134
 
120
135
  ### Dottie Usage Options
data/Rakefile CHANGED
@@ -2,7 +2,7 @@ require 'rspec/core/rake_task'
2
2
  require 'bundler/gem_tasks'
3
3
 
4
4
  RSpec::Core::RakeTask.new(:spec) do |task|
5
- task.rspec_opts = ['--color', '--format', 'nested']
5
+ task.rspec_opts = ['--color', '--format', 'progress']
6
6
  end
7
7
 
8
8
  task default: :spec
data/dottie.gemspec CHANGED
@@ -20,7 +20,7 @@ Gem::Specification.new do |spec|
20
20
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
21
21
  spec.require_paths = ["lib"]
22
22
 
23
- spec.add_development_dependency "bundler", "~> 1.5"
23
+ spec.add_development_dependency "bundler", ">= 2.2.33"
24
24
  spec.add_development_dependency "rake"
25
25
  spec.add_development_dependency "rspec"
26
26
  end
@@ -6,7 +6,12 @@ module Dottie
6
6
  # Creates a new Freckle to wrap the supplied object.
7
7
 
8
8
  def initialize(obj)
9
- @_wrapped_object = obj
9
+ case obj
10
+ when Hash, Array
11
+ @_wrapped_object = obj
12
+ else
13
+ raise TypeError, 'must be a Hash or Array'
14
+ end
10
15
  end
11
16
 
12
17
  ##
@@ -56,6 +56,31 @@ module Dottie
56
56
  end
57
57
  end
58
58
 
59
+ ##
60
+ # Deletes the value at the specified key and returns it.
61
+
62
+ def delete(key)
63
+ if Dottie.dottie_key?(key)
64
+ Dottie.delete(wrapped_object_or_self, key)
65
+ else
66
+ super
67
+ end
68
+ end
69
+
70
+ ##
71
+ #
72
+
73
+ def dottie_flatten
74
+ Dottie.flatten(wrapped_object_or_self)
75
+ end
76
+
77
+ ##
78
+ #
79
+
80
+ def dottie_keys(intermediate = false)
81
+ Dottie.keys(wrapped_object_or_self, intermediate: intermediate)
82
+ end
83
+
59
84
  private
60
85
 
61
86
  ##
@@ -1,3 +1,3 @@
1
1
  module Dottie
2
- VERSION = '0.0.1'
2
+ VERSION = '0.0.3'
3
3
  end
data/lib/dottie.rb CHANGED
@@ -10,7 +10,11 @@ module Dottie
10
10
  # Creates a new Dottie::Freckle from a standard Ruby Hash or Array.
11
11
 
12
12
  def self.[](obj)
13
- Dottie::Freckle.new(obj)
13
+ if obj.is_a?(Dottie::Freckle)
14
+ obj
15
+ else
16
+ Dottie::Freckle.new(obj)
17
+ end
14
18
  end
15
19
 
16
20
  ##
@@ -21,6 +25,8 @@ module Dottie
21
25
  Dottie.key_parts(key).each do |k|
22
26
  obj = case obj
23
27
  when Hash, Array
28
+ # use an array index if it appears that's what was intended
29
+ k = k.to_i if obj.is_a?(Array) && k.to_i.to_s == k
24
30
  obj[k]
25
31
  else
26
32
  nil
@@ -39,8 +45,17 @@ module Dottie
39
45
  # set the value if this is the last key part
40
46
  if i == key_parts.size - 1
41
47
  case obj
42
- when Hash, Array
48
+ when Hash
43
49
  obj[k] = value
50
+ when Array
51
+ case k
52
+ when '-', 'prepend', '>>'
53
+ obj.unshift(value)
54
+ when '+', 'append', '<<'
55
+ obj << value
56
+ else
57
+ obj[k] = value
58
+ end
44
59
  else
45
60
  raise TypeError.new("expected Hash or Array but got #{obj.class.name}")
46
61
  end
@@ -49,7 +64,8 @@ module Dottie
49
64
  obj = case obj
50
65
  when Hash, Array
51
66
  # look ahead at the next key to see if an array should be created
52
- if key_parts[i + 1].is_a?(Integer)
67
+ if key_parts[i + 1].is_a?(Integer) ||
68
+ key_parts[i + 1] =~ /\A(-|\+|prepend|append|>>|<<)\z/
53
69
  obj[k] ||= []
54
70
  else
55
71
  obj[k] ||= {}
@@ -57,7 +73,7 @@ module Dottie
57
73
  when nil
58
74
  # look at the key to see if an array should be created
59
75
  case k
60
- when Integer
76
+ when Integer, '-', '+', 'prepend', 'append', '>>', '<<'
61
77
  obj[k] = []
62
78
  else
63
79
  obj[k] = {}
@@ -113,6 +129,71 @@ module Dottie
113
129
  end
114
130
  end
115
131
 
132
+ ##
133
+ # Deletes the value at the specified key and returns it.
134
+
135
+ def self.delete(obj, key)
136
+ if Dottie.has_key?(obj, key)
137
+ key_parts = Dottie.key_parts(key)
138
+ if key_parts.size > 1
139
+ key = Dottie.build_key(key_parts[0..-2])
140
+ obj = Dottie.get(obj, key)
141
+ end
142
+ if obj.is_a?(Array) && key_parts.last.is_a?(Integer)
143
+ obj.delete_at(key_parts.last)
144
+ else
145
+ obj.delete(key_parts.last)
146
+ end
147
+ else
148
+ nil
149
+ end
150
+ end
151
+
152
+ ##
153
+ # Flattens a Hash or Array to a single-depth Hash with Dottie-style keys.
154
+
155
+ def self.flatten(obj, options = {}, path = nil, flat = nil)
156
+ path ||= []
157
+ flat ||= {}
158
+ case obj
159
+ when Hash
160
+ obj.each do |k, v|
161
+ this_path = path + [k]
162
+ case v
163
+ when Hash, Array
164
+ flat[this_path.join('.')] = options[:keys_only] ? nil : v if options[:intermediate]
165
+ Dottie.flatten(v, options, this_path, flat)
166
+ else
167
+ flat[this_path.join('.')] = options[:keys_only] ? nil : v
168
+ end
169
+ end
170
+ when Array
171
+ obj.each_with_index do |v, i|
172
+ this_path = path.dup
173
+ if this_path.any?
174
+ this_path[-1] = this_path[-1].to_s + "[#{i}]"
175
+ else
176
+ this_path = ["[#{i}]"]
177
+ end
178
+ case v
179
+ when Hash, Array
180
+ flat[this_path.join('.')] = options[:keys_only] ? nil : v if options[:intermediate]
181
+ Dottie.flatten(v, options, this_path, flat)
182
+ else
183
+ flat[this_path.join('.')] = options[:keys_only] ? nil : v
184
+ end
185
+ end
186
+ end
187
+ flat
188
+ end
189
+
190
+ ##
191
+ # Gets an array of the Dottie-style keys that exist in a Hash or Array.
192
+
193
+ def self.keys(obj, options = {})
194
+ Dottie.flatten(obj, { keys_only: true }.merge(options)).keys
195
+ end
196
+
116
197
  ##
117
198
  # Checks whether a key looks like a key Dottie understands.
118
199
 
@@ -150,4 +231,21 @@ module Dottie
150
231
  end
151
232
  end
152
233
 
234
+ ##
235
+ # Builds a Dottie key from an Array of strings and integers.
236
+
237
+ def self.build_key(parts)
238
+ key = ''
239
+ parts.each_with_index do |part, i|
240
+ case part
241
+ when String
242
+ key << '.' unless i == 0
243
+ key << part
244
+ when Integer
245
+ key << "[#{part}]"
246
+ end
247
+ end
248
+ key
249
+ end
250
+
153
251
  end
data/spec/dottie_spec.rb CHANGED
@@ -20,6 +20,30 @@ describe Dottie do
20
20
  arr = ['a', 'b', 'c']
21
21
  expect(Dottie(arr)).to be_a Dottie::Freckle
22
22
  end
23
+ it 'returns a Dottie::Freckle<Hash> instead of rewrapping it using Dottie[]' do
24
+ dottie = Dottie[{ 'a' => 'b' }]
25
+ expect(Dottie[dottie]).to eq dottie
26
+ end
27
+ it 'returns a Dottie::Freckle<Array> instead of rewrapping it using Dottie[]' do
28
+ dottie = Dottie[['a', 'b', 'c']]
29
+ expect(Dottie[dottie]).to eq dottie
30
+ end
31
+ it 'returns a Dottie::Freckle<Hash> instead of rewrapping it using Dottie()' do
32
+ dottie = Dottie({ 'a' => 'b' })
33
+ expect(Dottie(dottie)).to eq dottie
34
+ end
35
+ it 'returns a Dottie::Freckle<Array> instead of rewrapping it using Dottie()' do
36
+ dottie = Dottie(['a', 'b', 'c'])
37
+ expect(Dottie(dottie)).to eq dottie
38
+ end
39
+ ['a', nil, 1].each do |val|
40
+ it "fails to create a Dottie::Freckle from an invalid type (#{val.class}) using Dottie[]" do
41
+ expect{ Dottie[val] }.to raise_error(TypeError)
42
+ end
43
+ it "fails to create a Dottie::Freckle from an invalid type (#{val.class}) using Dottie()" do
44
+ expect{ Dottie(val) }.to raise_error(TypeError)
45
+ end
46
+ end
23
47
 
24
48
  end
25
49
 
@@ -120,34 +144,48 @@ describe Dottie do
120
144
  end
121
145
  end
122
146
 
147
+ context 'lax keys' do
148
+ let(:hash) {{ 'a' => 'b', 'c' => [{ 'd' => 'e', '0' => 1 }, { 'f' => 'g' }] }}
149
+
150
+ it 'reads a targeted array index number as an integer' do
151
+ expect(Dottie.get(hash, 'c.0.d')).to eq 'e'
152
+ end
153
+ it 'reads a targeted hash key number as a string' do
154
+ expect(Dottie.get(hash, 'c.0.0')).to eq 1
155
+ end
156
+ it 'reads an targeted hash key integer as an integer' do
157
+ expect(Dottie.get(hash, 'c.0[0]')).to be_nil
158
+ end
159
+ end
160
+
123
161
  end
124
162
 
125
163
  describe 'key existence' do
126
164
  let(:hash) {{ 'a' => 'b', 'c' => { 'd' => ['e', 'f', 'g'] } }}
127
165
 
128
166
  it "finds a standard key" do
129
- expect(Dottie.has_key?(hash, 'a')).to be_true
167
+ expect(Dottie.has_key?(hash, 'a')).to be true
130
168
  end
131
169
  it "does not find a missing standard key" do
132
- expect(Dottie.has_key?(hash, 'x')).to be_false
170
+ expect(Dottie.has_key?(hash, 'x')).to be false
133
171
  end
134
172
  it "finds a Dottie key (Hash value)" do
135
- expect(Dottie.has_key?(hash, 'c.d')).to be_true
173
+ expect(Dottie.has_key?(hash, 'c.d')).to be true
136
174
  end
137
175
  it "finds a Dottie key (Array element)" do
138
- expect(Dottie.has_key?(hash, 'c.d[0]')).to be_true
176
+ expect(Dottie.has_key?(hash, 'c.d[0]')).to be true
139
177
  end
140
178
  it "does not find a missing Dottie key (first part is a String)" do
141
- expect(Dottie.has_key?(hash, 'a.b')).to be_false
179
+ expect(Dottie.has_key?(hash, 'a.b')).to be false
142
180
  end
143
181
  it "does not find a missing Dottie key (first part exists)" do
144
- expect(Dottie.has_key?(hash, 'c.x')).to be_false
182
+ expect(Dottie.has_key?(hash, 'c.x')).to be false
145
183
  end
146
184
  it "does not find a missing Dottie key (outside Array bounds)" do
147
- expect(Dottie.has_key?(hash, 'c.d[4]')).to be_false
185
+ expect(Dottie.has_key?(hash, 'c.d[4]')).to be false
148
186
  end
149
187
  it "does not find a missing Dottie key (no part exists)" do
150
- expect(Dottie.has_key?(hash, 'x.y')).to be_false
188
+ expect(Dottie.has_key?(hash, 'x.y')).to be false
151
189
  end
152
190
  end
153
191
 
@@ -255,6 +293,31 @@ describe Dottie do
255
293
  end
256
294
  end
257
295
 
296
+ context 'array prepend/append' do
297
+ before :each do
298
+ @hash = { 'a' => 'b', 'c' => ['g', 'h', 'i'] }
299
+ end
300
+
301
+ %w( - prepend >> ).each do |key|
302
+ it "prepends an array element with [#{key}]" do
303
+ Dottie.set(@hash, "c[#{key}]", 'f')
304
+ expect(@hash).to eq({ 'a' => 'b', 'c' => ['f', 'g', 'h', 'i'] })
305
+ end
306
+ end
307
+ %w( + append << ).each do |key|
308
+ it "appends an array element with [#{key}]" do
309
+ Dottie.set(@hash, "c[#{key}]", 'j')
310
+ expect(@hash).to eq({ 'a' => 'b', 'c' => ['g', 'h', 'i', 'j'] })
311
+ end
312
+ end
313
+ %w( - + prepend append >> << ).each do |key|
314
+ it "creates an array at a non-existent key with [#{key}]" do
315
+ Dottie.set(@hash, "r[#{key}]", 's')
316
+ expect(@hash).to eq({ 'a' => 'b', 'c' => ['g', 'h', 'i'], 'r' => ['s'] })
317
+ end
318
+ end
319
+ end
320
+
258
321
  context 'invalid' do
259
322
  before :each do
260
323
  @hash = { 'a' => 'b', 'c' => { 'd' => 'e' }, 'f' => ['g', 'h'] }
@@ -277,26 +340,130 @@ describe Dottie do
277
340
 
278
341
  end
279
342
 
343
+ describe 'deleting' do
344
+
345
+ context 'simple' do
346
+ before :each do
347
+ @hash = { 'a' => 'b', 'c' => { 'd' => 'e' } }
348
+ end
349
+
350
+ it 'deletes a standard key' do
351
+ ret = Dottie.delete(@hash, 'c')
352
+ expect(ret).to eq({ 'd' => 'e' })
353
+ expect(@hash).to eq({ 'a' => 'b' })
354
+ end
355
+ it 'deletes a dotted key' do
356
+ ret = Dottie.delete(@hash, 'c.d')
357
+ expect(ret).to eq 'e'
358
+ expect(@hash).to eq({ 'a' => 'b', 'c' => {} })
359
+ end
360
+ it 'returns nil when attempting to delete a non-existent standard key' do
361
+ ret = Dottie.delete(@hash, 'x')
362
+ expect(ret).to be_nil
363
+ expect(@hash).to eq({ 'a' => 'b', 'c' => { 'd' => 'e' } })
364
+ end
365
+ it 'returns nil when attempting to delete a non-existent dotted key' do
366
+ ret = Dottie.delete(@hash, 'x.y')
367
+ expect(ret).to be_nil
368
+ expect(@hash).to eq({ 'a' => 'b', 'c' => { 'd' => 'e' } })
369
+ end
370
+ end
371
+
372
+ context 'array indexes' do
373
+ before :each do
374
+ @hash = { 'a' => 'b', 'c' => [{ 'd' => 'e', 'f' => 'g' }, { 'h' => 'i' }] }
375
+ end
376
+
377
+ it 'deletes an element from an array (positive index)' do
378
+ ret = Dottie.delete(@hash, 'c[0]')
379
+ expect(ret).to eq({ 'd' => 'e', 'f' => 'g' })
380
+ expect(@hash).to eq({ 'a' => 'b', 'c' => [{ 'h' => 'i' }] })
381
+ end
382
+ it 'deletes an element from an array (negative index)' do
383
+ ret = Dottie.delete(@hash, 'c[-1]')
384
+ expect(ret).to eq({ 'h' => 'i' })
385
+ expect(@hash).to eq({ 'a' => 'b', 'c' => [{ 'd' => 'e', 'f' => 'g' }] })
386
+ end
387
+ it 'deletes an element from an array (first)' do
388
+ ret = Dottie.delete(@hash, 'c[first]')
389
+ expect(ret).to eq({ 'd' => 'e', 'f' => 'g' })
390
+ expect(@hash).to eq({ 'a' => 'b', 'c' => [{ 'h' => 'i' }] })
391
+ end
392
+ it 'deletes an element from an array (last)' do
393
+ ret = Dottie.delete(@hash, 'c[last]')
394
+ expect(ret).to eq({ 'h' => 'i' })
395
+ expect(@hash).to eq({ 'a' => 'b', 'c' => [{ 'd' => 'e', 'f' => 'g' }] })
396
+ end
397
+ it 'deletes an element from a nested structure' do
398
+ ret = Dottie.delete(@hash, 'c[0].d')
399
+ expect(ret).to eq('e')
400
+ expect(@hash).to eq({ 'a' => 'b', 'c' => [{ 'f' => 'g' }, { 'h' => 'i' }] })
401
+ end
402
+ it 'returns nil when attempting to delete a non-existent array index' do
403
+ ret = Dottie.delete(@hash, 'c[3]')
404
+ expect(ret).to be_nil
405
+ expect(@hash).to eq({ 'a' => 'b', 'c' => [{ 'd' => 'e', 'f' => 'g' }, { 'h' => 'i' }] })
406
+ end
407
+ end
408
+
409
+ end
410
+
411
+ describe 'flattening' do
412
+
413
+ context 'hash' do
414
+ let(:hash) {{ 'a' => 'b', 'c' => { 'd' => ['e', 'f', 'g'] } }}
415
+
416
+ it 'flattens a hash' do
417
+ expect(Dottie.flatten(hash)).to eq({ 'a' => 'b', 'c.d[0]' => 'e', 'c.d[1]' => 'f', 'c.d[2]' => 'g' })
418
+ end
419
+ it 'gets flattened hash keys' do
420
+ expect(Dottie.keys(hash)).to eq ['a', 'c.d[0]', 'c.d[1]', 'c.d[2]']
421
+ end
422
+ it 'gets all flattened hash keys' do
423
+ expect(Dottie.keys(hash, intermediate: true)).to eq ['a', 'c', 'c.d', 'c.d[0]', 'c.d[1]', 'c.d[2]']
424
+ end
425
+ end
426
+
427
+ context 'array' do
428
+ let(:arr) { ['x', { 'a' => 'b', 'c' => { 'd' => ['e', 'f', 'g'] } }, 'y'] }
429
+
430
+ it 'flattens an array' do
431
+ expect(Dottie.flatten(arr)).to eq({
432
+ '[0]' => 'x',
433
+ '[1].a' => 'b', '[1].c.d[0]' => 'e', '[1].c.d[1]' => 'f', '[1].c.d[2]' => 'g',
434
+ '[2]' => 'y' })
435
+ end
436
+ it 'gets flattened array keys' do
437
+ expect(Dottie.keys(arr)).to eq ['[0]', '[1].a', '[1].c.d[0]', '[1].c.d[1]', '[1].c.d[2]', '[2]']
438
+ end
439
+ it 'gets all flattened array keys' do
440
+ expect(Dottie.keys(arr, intermediate: true)).to eq [
441
+ '[0]', '[1]', '[1].a', '[1].c', '[1].c.d', '[1].c.d[0]', '[1].c.d[1]', '[1].c.d[2]', '[2]']
442
+ end
443
+ end
444
+
445
+ end
446
+
280
447
  describe 'key identification' do
281
448
 
282
449
  it 'recognizes a dotted key' do
283
450
  key = 'a.b.c'
284
- expect(Dottie.dottie_key?(key)).to be_true
451
+ expect(Dottie.dottie_key?(key)).to be true
285
452
  end
286
453
 
287
454
  it 'recognizes a bracketed key' do
288
455
  key = 'a[0]b'
289
- expect(Dottie.dottie_key?(key)).to be_true
456
+ expect(Dottie.dottie_key?(key)).to be true
290
457
  end
291
458
 
292
459
  it 'recognizes an array as a Dottie key' do
293
460
  key = ['a', 'b', 'c']
294
- expect(Dottie.dottie_key?(key)).to be_true
461
+ expect(Dottie.dottie_key?(key)).to be true
295
462
  end
296
463
 
297
464
  it 'does not recognize a normal key' do
298
465
  key = 'a_b_c'
299
- expect(Dottie.dottie_key?(key)).to be_false
466
+ expect(Dottie.dottie_key?(key)).to be false
300
467
  end
301
468
 
302
469
  end
@@ -400,6 +567,34 @@ describe Dottie do
400
567
 
401
568
  end
402
569
 
570
+ describe 'key building' do
571
+
572
+ it 'builds a single-element key' do
573
+ expect(Dottie.build_key(['a'])).to eq 'a'
574
+ end
575
+
576
+ it 'builds a dotted key' do
577
+ expect(Dottie.build_key(['a', 'b', 'c'])).to eq 'a.b.c'
578
+ end
579
+
580
+ it 'builds a dotted key a number' do
581
+ expect(Dottie.build_key(['a', '0', '1', 'b'])).to eq 'a.0.1.b'
582
+ end
583
+
584
+ it 'builds a complex key with a positive integer' do
585
+ expect(Dottie.build_key(['a', 0, 'b'])).to eq 'a[0].b'
586
+ end
587
+
588
+ it 'builds a complex key with a negative integer' do
589
+ expect(Dottie.build_key(['a', -1, 'b'])).to eq 'a[-1].b'
590
+ end
591
+
592
+ it 'builds a complex key with consecutive integers' do
593
+ expect(Dottie.build_key(['a', 0, 1, 'b'])).to eq 'a[0][1].b'
594
+ end
595
+
596
+ end
597
+
403
598
  describe 'key format variants' do
404
599
  let(:arr) { ['a', 0, 'b', 1, 'c', -2, 'd', -1, 'e'] }
405
600
 
data/spec/freckle_spec.rb CHANGED
@@ -2,6 +2,22 @@ require 'spec_helper'
2
2
 
3
3
  describe Dottie::Freckle do
4
4
 
5
+ describe 'instantiation' do
6
+
7
+ it 'creates a Dottie::Freckle from a Hash' do
8
+ expect(Dottie::Freckle.new({ 'a' => 'b' })).to be_a Dottie::Freckle
9
+ end
10
+ it 'creates a Dottie::Freckle from an Array' do
11
+ expect(Dottie::Freckle.new(['a', 'b', 'c'])).to be_a Dottie::Freckle
12
+ end
13
+ ['a', nil, 1].each do |val|
14
+ it "fails to create a Dottie::Freckle from an invalid type (#{val.class})" do
15
+ expect{ Dottie::Freckle.new(val) }.to raise_error(TypeError)
16
+ end
17
+ end
18
+
19
+ end
20
+
5
21
  describe 'general' do
6
22
 
7
23
  context 'Hash' do
@@ -131,28 +147,28 @@ describe Dottie::Freckle do
131
147
  let(:freckle) { Dottie::Freckle.new({ 'a' => 'b', 'c' => { 'd' => ['e', 'f', 'g'] } }) }
132
148
 
133
149
  it "finds a standard key" do
134
- expect(freckle.has_key?('a')).to be_true
150
+ expect(freckle.has_key?('a')).to be true
135
151
  end
136
152
  it "does not find a missing standard key" do
137
- expect(freckle.has_key?('x')).to be_false
153
+ expect(freckle.has_key?('x')).to be false
138
154
  end
139
155
  it "finds a Dottie key (Hash value)" do
140
- expect(freckle.has_key?('c.d')).to be_true
156
+ expect(freckle.has_key?('c.d')).to be true
141
157
  end
142
158
  it "finds a Dottie key (Array element)" do
143
- expect(freckle.has_key?('c.d[0]')).to be_true
159
+ expect(freckle.has_key?('c.d[0]')).to be true
144
160
  end
145
161
  it "does not find a missing Dottie key (first part is a String)" do
146
- expect(freckle.has_key?('a.b')).to be_false
162
+ expect(freckle.has_key?('a.b')).to be false
147
163
  end
148
164
  it "does not find a missing Dottie key (first part exists)" do
149
- expect(freckle.has_key?('c.x')).to be_false
165
+ expect(freckle.has_key?('c.x')).to be false
150
166
  end
151
167
  it "does not find a missing Dottie key (outside Array bounds)" do
152
- expect(freckle.has_key?('c.d[4]')).to be_false
168
+ expect(freckle.has_key?('c.d[4]')).to be false
153
169
  end
154
170
  it "does not find a missing Dottie key (no part exists)" do
155
- expect(freckle.has_key?('x.y')).to be_false
171
+ expect(freckle.has_key?('x.y')).to be false
156
172
  end
157
173
  end
158
174
 
@@ -271,4 +287,40 @@ describe Dottie::Freckle do
271
287
 
272
288
  end
273
289
 
290
+ describe 'flattening' do
291
+
292
+ context 'hash' do
293
+ let(:freckle) { Dottie::Freckle.new({ 'a' => 'b', 'c' => { 'd' => ['e', 'f', 'g'] } }) }
294
+
295
+ it 'flattens a hash' do
296
+ expect(freckle.dottie_flatten).to eq({ 'a' => 'b', 'c.d[0]' => 'e', 'c.d[1]' => 'f', 'c.d[2]' => 'g' })
297
+ end
298
+ it 'gets flattened hash keys' do
299
+ expect(freckle.dottie_keys).to eq ['a', 'c.d[0]', 'c.d[1]', 'c.d[2]']
300
+ end
301
+ it 'gets all flattened hash keys' do
302
+ expect(freckle.dottie_keys(true)).to eq ['a', 'c', 'c.d', 'c.d[0]', 'c.d[1]', 'c.d[2]']
303
+ end
304
+ end
305
+
306
+ context 'array' do
307
+ let(:freckle) { Dottie::Freckle.new(['x', { 'a' => 'b', 'c' => { 'd' => ['e', 'f', 'g'] } }, 'y']) }
308
+
309
+ it 'flattens an array' do
310
+ expect(freckle.dottie_flatten).to eq({
311
+ '[0]' => 'x',
312
+ '[1].a' => 'b', '[1].c.d[0]' => 'e', '[1].c.d[1]' => 'f', '[1].c.d[2]' => 'g',
313
+ '[2]' => 'y' })
314
+ end
315
+ it 'gets flattened array keys' do
316
+ expect(freckle.dottie_keys).to eq ['[0]', '[1].a', '[1].c.d[0]', '[1].c.d[1]', '[1].c.d[2]', '[2]']
317
+ end
318
+ it 'gets all flattened array keys' do
319
+ expect(freckle.dottie_keys(true)).to eq [
320
+ '[0]', '[1]', '[1].a', '[1].c', '[1].c.d', '[1].c.d[0]', '[1].c.d[1]', '[1].c.d[2]', '[2]']
321
+ end
322
+ end
323
+
324
+ end
325
+
274
326
  end
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dottie
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nick Pearson
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-05-08 00:00:00.000000000 Z
11
+ date: 2024-03-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '1.5'
19
+ version: 2.2.33
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '1.5'
26
+ version: 2.2.33
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -85,7 +85,7 @@ homepage: https://github.com/nickpearson/dottie
85
85
  licenses:
86
86
  - MIT
87
87
  metadata: {}
88
- post_install_message:
88
+ post_install_message:
89
89
  rdoc_options: []
90
90
  require_paths:
91
91
  - lib
@@ -100,9 +100,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
100
100
  - !ruby/object:Gem::Version
101
101
  version: '0'
102
102
  requirements: []
103
- rubyforge_project:
104
- rubygems_version: 2.2.2
105
- signing_key:
103
+ rubygems_version: 3.2.33
104
+ signing_key:
106
105
  specification_version: 4
107
106
  summary: Deep Hash and Array access with dotted keys
108
107
  test_files:
@@ -111,4 +110,3 @@ test_files:
111
110
  - spec/freckle_spec.rb
112
111
  - spec/hash_spec.rb
113
112
  - spec/spec_helper.rb
114
- has_rdoc: