map 4.2.0 → 4.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +1 -0
- data/README +4 -0
- data/Rakefile +4 -2
- data/a.rb +7 -0
- data/lib/map.rb +83 -20
- data/map.gemspec +4 -2
- data/test/lib/testing.rb +1 -1
- data/test/map_test.rb +34 -0
- metadata +6 -4
data/LICENSE
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
same as ruby's
|
data/README
CHANGED
data/Rakefile
CHANGED
@@ -3,6 +3,9 @@ This.author = "Ara T. Howard"
|
|
3
3
|
This.email = "ara.t.howard@gmail.com"
|
4
4
|
This.homepage = "https://github.com/ahoward/#{ This.lib }"
|
5
5
|
|
6
|
+
task :license do
|
7
|
+
open('LICENSE', 'w'){|fd| fd.puts "same as ruby's"}
|
8
|
+
end
|
6
9
|
|
7
10
|
task :default do
|
8
11
|
puts((Rake::Task.tasks.map{|task| task.name.gsub(/::/,':')} - ['default']).sort)
|
@@ -26,11 +29,10 @@ def run_tests!(which = nil)
|
|
26
29
|
|
27
30
|
div = ('=' * 119)
|
28
31
|
line = ('-' * 119)
|
29
|
-
helper = "-r ./test/helper.rb" if test(?e, "./test/helper.rb")
|
30
32
|
|
31
33
|
test_rbs.each_with_index do |test_rb, index|
|
32
34
|
testno = index + 1
|
33
|
-
command = "#{ This.ruby } -I ./lib -I ./test/lib #{
|
35
|
+
command = "#{ This.ruby } -I ./lib -I ./test/lib #{ test_rb }"
|
34
36
|
|
35
37
|
puts
|
36
38
|
say(div, :color => :cyan, :bold => true)
|
data/a.rb
ADDED
data/lib/map.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
class Map < Hash
|
2
|
-
Version = '4.
|
2
|
+
Version = '4.3.0' unless defined?(Version)
|
3
3
|
Load = Kernel.method(:load) unless defined?(Load)
|
4
4
|
|
5
5
|
class << Map
|
@@ -184,6 +184,8 @@ class Map < Hash
|
|
184
184
|
when 1
|
185
185
|
first = args.first
|
186
186
|
case first
|
187
|
+
when nil, false
|
188
|
+
nil
|
187
189
|
when Hash
|
188
190
|
initialize_from_hash(first)
|
189
191
|
when Array
|
@@ -227,9 +229,16 @@ class Map < Hash
|
|
227
229
|
klass.map_for(hash)
|
228
230
|
end
|
229
231
|
|
232
|
+
=begin
|
230
233
|
def self.convert_key(key)
|
231
234
|
key.kind_of?(Symbol) ? key.to_s : key
|
232
235
|
end
|
236
|
+
=end
|
237
|
+
|
238
|
+
def self.convert_key(key)
|
239
|
+
key = key.kind_of?(Symbol) ? key.to_s : key
|
240
|
+
end
|
241
|
+
|
233
242
|
def convert_key(key)
|
234
243
|
if klass.respond_to?(:convert_key)
|
235
244
|
klass.convert_key(key)
|
@@ -312,11 +321,13 @@ class Map < Hash
|
|
312
321
|
alias_method 'store', '[]='
|
313
322
|
|
314
323
|
def [](key)
|
315
|
-
|
324
|
+
key = convert_key(key)
|
325
|
+
__get__(key)
|
316
326
|
end
|
317
327
|
|
318
328
|
def fetch(key, *args, &block)
|
319
|
-
|
329
|
+
key = convert_key(key)
|
330
|
+
super(key, *args, &block)
|
320
331
|
end
|
321
332
|
|
322
333
|
def key?(key)
|
@@ -553,19 +564,11 @@ class Map < Hash
|
|
553
564
|
hash
|
554
565
|
end
|
555
566
|
|
556
|
-
def
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
end
|
562
|
-
|
563
|
-
def class
|
564
|
-
@class || super
|
565
|
-
end
|
566
|
-
|
567
|
-
def to_yaml(*args, &block)
|
568
|
-
as_hash{ super }
|
567
|
+
def to_yaml( opts = {} )
|
568
|
+
map = self
|
569
|
+
YAML.quick_emit(self.object_id, opts){|out|
|
570
|
+
out.map('!omap'){|m| map.each{|k,v| m.add(k, v)}}
|
571
|
+
}
|
569
572
|
end
|
570
573
|
|
571
574
|
def to_array
|
@@ -625,8 +628,14 @@ class Map < Hash
|
|
625
628
|
# support for compound key indexing and depth first iteration
|
626
629
|
#
|
627
630
|
def get(*keys)
|
628
|
-
keys = keys
|
629
|
-
|
631
|
+
keys = key_for(keys)
|
632
|
+
if keys.size <= 1
|
633
|
+
if !self.has_key?(keys.first) && block_given?
|
634
|
+
return yield
|
635
|
+
else
|
636
|
+
return self[keys.first]
|
637
|
+
end
|
638
|
+
end
|
630
639
|
keys, key = keys[0..-2], keys[-1]
|
631
640
|
collection = self
|
632
641
|
keys.each do |k|
|
@@ -634,11 +643,17 @@ class Map < Hash
|
|
634
643
|
collection = collection[k]
|
635
644
|
return collection unless collection.respond_to?('[]')
|
636
645
|
end
|
637
|
-
|
646
|
+
alphanumeric_key = alphanumeric_key_for(key)
|
647
|
+
|
648
|
+
if !collection_has_key?(collection, alphanumeric_key) && block_given?
|
649
|
+
yield
|
650
|
+
else
|
651
|
+
collection[alphanumeric_key]
|
652
|
+
end
|
638
653
|
end
|
639
654
|
|
640
655
|
def has?(*keys)
|
641
|
-
keys = keys
|
656
|
+
keys = key_for(keys)
|
642
657
|
collection = self
|
643
658
|
return collection_has_key?(collection, keys.first) if keys.size <= 1
|
644
659
|
keys, key = keys[0..-2], keys[-1]
|
@@ -695,6 +710,9 @@ class Map < Hash
|
|
695
710
|
keys = Array(keys).flatten
|
696
711
|
|
697
712
|
collection = self
|
713
|
+
|
714
|
+
keys = key_for(keys)
|
715
|
+
|
698
716
|
if keys.size <= 1
|
699
717
|
key = keys.first
|
700
718
|
collection[key] = value
|
@@ -789,6 +807,51 @@ class Map < Hash
|
|
789
807
|
Map.alphanumeric_key_for(key)
|
790
808
|
end
|
791
809
|
|
810
|
+
## key path support
|
811
|
+
#
|
812
|
+
def self.dot_key_for(*keys)
|
813
|
+
dot = keys.compact.flatten.join('.')
|
814
|
+
dot.split(%r/\s*[,.:_-]\s*/).map{|part| part =~ %r/^\d+$/ ? Integer(part) : part}
|
815
|
+
end
|
816
|
+
|
817
|
+
def self.dot_keys
|
818
|
+
@@dot_keys = {} unless defined?(@@dot_keys)
|
819
|
+
@@dot_keys
|
820
|
+
end
|
821
|
+
|
822
|
+
def self.dot_keys?
|
823
|
+
ancestors.each do |ancestor|
|
824
|
+
return dot_keys[ancestor] if dot_keys.has_key?(ancestor)
|
825
|
+
end
|
826
|
+
false
|
827
|
+
end
|
828
|
+
|
829
|
+
def dot_keys?
|
830
|
+
@dot_keys = false unless defined?(@dot_keys)
|
831
|
+
@dot_keys
|
832
|
+
end
|
833
|
+
|
834
|
+
def self.dot_keys!(boolean = true)
|
835
|
+
dot_keys[self] = !!boolean
|
836
|
+
end
|
837
|
+
|
838
|
+
def dot_keys!(boolean = true)
|
839
|
+
@dot_keys = !!boolean
|
840
|
+
end
|
841
|
+
|
842
|
+
def self.key_for(*keys)
|
843
|
+
return keys.flatten unless dot_keys?
|
844
|
+
self.dot_key_for(*keys)
|
845
|
+
end
|
846
|
+
|
847
|
+
def key_for(*keys)
|
848
|
+
if dot_keys?
|
849
|
+
self.class.dot_key_for(*keys)
|
850
|
+
else
|
851
|
+
self.class.key_for(*keys)
|
852
|
+
end
|
853
|
+
end
|
854
|
+
|
792
855
|
## TODO - technically this returns only leaves so the name isn't *quite* right. re-factor for 3.0
|
793
856
|
#
|
794
857
|
def Map.depth_first_each(enumerable, path = [], accum = [], &block)
|
data/map.gemspec
CHANGED
@@ -3,15 +3,17 @@
|
|
3
3
|
|
4
4
|
Gem::Specification::new do |spec|
|
5
5
|
spec.name = "map"
|
6
|
-
spec.version = "4.
|
6
|
+
spec.version = "4.3.0"
|
7
7
|
spec.platform = Gem::Platform::RUBY
|
8
8
|
spec.summary = "map"
|
9
9
|
spec.description = "description: map kicks the ass"
|
10
10
|
|
11
11
|
spec.files =
|
12
|
-
["
|
12
|
+
["LICENSE",
|
13
|
+
"README",
|
13
14
|
"Rakefile",
|
14
15
|
"TODO",
|
16
|
+
"a.rb",
|
15
17
|
"lib",
|
16
18
|
"lib/map",
|
17
19
|
"lib/map.rb",
|
data/test/lib/testing.rb
CHANGED
data/test/map_test.rb
CHANGED
@@ -24,6 +24,11 @@ Testing Map do
|
|
24
24
|
assert{ Map.new(*array) }
|
25
25
|
end
|
26
26
|
|
27
|
+
testing 'that the constructor does not die when passed nil or false' do
|
28
|
+
assert{ Map.new(nil) }
|
29
|
+
assert{ Map.new(false) }
|
30
|
+
end
|
31
|
+
|
27
32
|
testing 'that the contructor accepts an even sized array' do
|
28
33
|
arrays = [
|
29
34
|
[ %w( k v ), %w( key val ) ],
|
@@ -327,6 +332,35 @@ Testing Map do
|
|
327
332
|
assert{ m[:x][:y][:z] == 42.0 }
|
328
333
|
end
|
329
334
|
|
335
|
+
testing 'that maps can support compound key/val setting via key.dot notation' do
|
336
|
+
m = Class.new(Map){ dot_keys! }.new
|
337
|
+
assert{ m.set('a.b.c', 42) }
|
338
|
+
assert{ m[:a][:b][:c] == 42 }
|
339
|
+
assert{ m.get('a.b.c') == 42 }
|
340
|
+
assert{ m.set('x.y.z' => 42.0, 'A.2' => 'forty-two') }
|
341
|
+
assert{ m[:A].is_a?(Array) }
|
342
|
+
assert{ m[:A].size == 3}
|
343
|
+
assert{ m[:A][2] == 'forty-two' }
|
344
|
+
assert{ m[:x][:y].is_a?(Hash) }
|
345
|
+
assert{ m[:x][:y][:z] == 42.0 }
|
346
|
+
assert{ m.has?('a.b.c') }
|
347
|
+
assert{ m.has?('x.y.z') }
|
348
|
+
assert{ m.has?('A.2') }
|
349
|
+
end
|
350
|
+
|
351
|
+
testing 'that Map#get supports providing a default value in a block' do
|
352
|
+
m = Map.new
|
353
|
+
m.set(:a, :b, :c, 42)
|
354
|
+
m.set(:z, 1)
|
355
|
+
|
356
|
+
assert { m.get(:x) {1} == 1 }
|
357
|
+
assert { m.get(:z) {2} == 1 }
|
358
|
+
assert { m.get(:a, :b, :d) {1} == 1 }
|
359
|
+
assert { m.get(:a, :b, :c) {1} == 42 }
|
360
|
+
assert { m.get(:a, :b) {1} == Map.new({:c => 42}) }
|
361
|
+
assert { m.get(:a, :aa) {1} == 1 }
|
362
|
+
end
|
363
|
+
|
330
364
|
testing 'that setting a sub-container does not eff up the container values' do
|
331
365
|
m = Map.new
|
332
366
|
assert{ m.set(:array => [0,1,2]) }
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: map
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 51
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 4
|
8
|
-
-
|
8
|
+
- 3
|
9
9
|
- 0
|
10
|
-
version: 4.
|
10
|
+
version: 4.3.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Ara T. Howard
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
18
|
+
date: 2011-08-17 00:00:00 -06:00
|
19
19
|
default_executable:
|
20
20
|
dependencies: []
|
21
21
|
|
@@ -28,9 +28,11 @@ extensions: []
|
|
28
28
|
extra_rdoc_files: []
|
29
29
|
|
30
30
|
files:
|
31
|
+
- LICENSE
|
31
32
|
- README
|
32
33
|
- Rakefile
|
33
34
|
- TODO
|
35
|
+
- a.rb
|
34
36
|
- lib/map.rb
|
35
37
|
- lib/map/options.rb
|
36
38
|
- lib/map/struct.rb
|