map 5.6.1 → 5.8.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.
- data/a.rb +41 -5
- data/lib/map.rb +128 -45
- data/map.gemspec +1 -1
- data/test/map_test.rb +70 -1
- metadata +3 -3
data/a.rb
CHANGED
@@ -1,20 +1,56 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
|
3
2
|
# -*- encoding : utf-8 -*-
|
4
3
|
|
4
|
+
require './lib/map.rb'
|
5
|
+
|
6
|
+
|
5
7
|
def assert(&block)
|
6
8
|
block.call
|
7
9
|
end
|
8
10
|
|
11
|
+
|
12
|
+
###
|
9
13
|
m = Map.new
|
10
|
-
m.
|
11
|
-
|
14
|
+
p m.add(
|
15
|
+
:comments => [
|
16
|
+
{ :body => 'a' },
|
17
|
+
{ :body => 'b' },
|
18
|
+
],
|
19
|
+
|
20
|
+
[:comments, 0] => {'title' => 'teh title', 'description' => 'description'},
|
21
|
+
[:comments, 1] => {'description' => 'description'},
|
22
|
+
)
|
23
|
+
puts
|
24
|
+
puts
|
25
|
+
p :m => m
|
12
26
|
|
13
27
|
|
28
|
+
__END__
|
29
|
+
=begin
|
14
30
|
|
31
|
+
{"comments"=>
|
32
|
+
[{"body"=>"a", "title"=>"teh title", "description"=>"description"},
|
33
|
+
{"body"=>"b", "description"=>"description"}]}
|
34
|
+
|
35
|
+
=end
|
36
|
+
|
37
|
+
|
38
|
+
###
|
15
39
|
m = Map.new
|
16
|
-
m.
|
17
|
-
|
40
|
+
p m.add(
|
41
|
+
[:a, :b, :c] => 42,
|
42
|
+
|
43
|
+
[:a, :b] => {:d => 42.0}
|
44
|
+
)
|
45
|
+
puts
|
46
|
+
puts
|
47
|
+
p m
|
48
|
+
|
49
|
+
=begin
|
18
50
|
|
51
|
+
{"a"=>{"b"=>{"c"=>42, "d"=>42.0}}}
|
19
52
|
|
53
|
+
=end
|
20
54
|
|
55
|
+
Map.new.add
|
56
|
+
Map.new.add({})
|
data/lib/map.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
2
2
|
class Map < Hash
|
3
|
-
Version = '5.
|
3
|
+
Version = '5.8.0' unless defined?(Version)
|
4
4
|
Load = Kernel.method(:load) unless defined?(Load)
|
5
5
|
|
6
6
|
class << Map
|
@@ -726,79 +726,162 @@ class Map < Hash
|
|
726
726
|
end
|
727
727
|
|
728
728
|
def set(*args)
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
729
|
+
case
|
730
|
+
when args.empty?
|
731
|
+
return []
|
732
|
+
when args.size == 1 && args.first.is_a?(Hash)
|
733
|
+
hash = args.shift
|
734
|
+
else
|
735
|
+
hash = {}
|
736
|
+
value = args.pop
|
737
|
+
key = Array(args).flatten
|
738
|
+
hash[key] = value
|
736
739
|
end
|
737
740
|
|
738
|
-
|
739
|
-
spec.each do |keys, value|
|
740
|
-
keys = Array(keys).flatten
|
741
|
-
collection = self
|
742
|
-
key = keys.pop
|
743
|
-
|
744
|
-
while((k = keys.shift)) do
|
745
|
-
k = alphanumeric_key_for(k)
|
746
|
-
collection = collection[k]
|
747
|
-
end
|
741
|
+
strategy = hash.map{|key, value| [Array(key), value]}
|
748
742
|
|
749
|
-
|
743
|
+
strategy.each do |key, value|
|
744
|
+
leaf_for(key, :autovivify => true) do |leaf, k|
|
745
|
+
leaf[k] = value
|
750
746
|
end
|
751
|
-
|
752
|
-
|
753
|
-
|
747
|
+
end
|
748
|
+
|
749
|
+
self
|
750
|
+
end
|
751
|
+
|
752
|
+
def add(*args)
|
753
|
+
case
|
754
|
+
when args.empty?
|
755
|
+
return []
|
756
|
+
when args.size == 1 && args.first.is_a?(Hash)
|
757
|
+
hash = args.shift
|
758
|
+
else
|
759
|
+
hash = {}
|
760
|
+
value = args.pop
|
761
|
+
key = Array(args).flatten
|
762
|
+
hash[key] = value
|
763
|
+
end
|
764
|
+
|
765
|
+
exploded = Map.explode(hash)
|
766
|
+
|
767
|
+
exploded[:branches].each do |key, type|
|
768
|
+
set(key, type.new) unless get(key).is_a?(type)
|
769
|
+
end
|
770
|
+
|
771
|
+
exploded[:leaves].each do |key, value|
|
772
|
+
set(key, value)
|
773
|
+
end
|
774
|
+
|
775
|
+
self
|
776
|
+
end
|
777
|
+
|
778
|
+
def Map.explode(hash)
|
779
|
+
accum = {:branches => [], :leaves => []}
|
780
|
+
|
781
|
+
hash.each do |key, value|
|
782
|
+
Map._explode(key, value, accum)
|
783
|
+
end
|
784
|
+
|
785
|
+
branches = accum[:branches]
|
786
|
+
leaves = accum[:leaves]
|
787
|
+
|
788
|
+
sort_by_key_size = proc{|a,b| a.first.size <=> b.first.size}
|
789
|
+
|
790
|
+
branches.sort!(&sort_by_key_size)
|
791
|
+
leaves.sort!(&sort_by_key_size)
|
792
|
+
|
793
|
+
accum
|
794
|
+
end
|
754
795
|
|
755
|
-
|
796
|
+
def Map._explode(key, value, accum = {:branches => [], :leaves => []})
|
797
|
+
key = Array(key).flatten
|
756
798
|
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
799
|
+
case value
|
800
|
+
when Array
|
801
|
+
accum[:branches].push([key, Array])
|
802
|
+
|
803
|
+
value.each_with_index do |v, k|
|
804
|
+
Map._explode(key + [k], v, accum)
|
761
805
|
end
|
762
806
|
|
763
|
-
|
764
|
-
|
807
|
+
when Hash
|
808
|
+
accum[:branches].push([key, Map])
|
809
|
+
|
810
|
+
value.each do |k, v|
|
811
|
+
Map._explode(key + [k], v, accum)
|
765
812
|
end
|
766
|
-
|
813
|
+
|
814
|
+
else
|
815
|
+
accum[:leaves].push([key, value])
|
767
816
|
end
|
768
817
|
|
769
|
-
|
818
|
+
accum
|
770
819
|
end
|
771
820
|
|
772
|
-
def
|
773
|
-
|
774
|
-
|
821
|
+
def Map.add(*args)
|
822
|
+
args.flatten!
|
823
|
+
args.compact!
|
824
|
+
|
825
|
+
Map.for(args.shift).tap do |map|
|
826
|
+
args.each{|arg| map.add(arg)}
|
827
|
+
end
|
828
|
+
end
|
829
|
+
|
830
|
+
def Map.combine(*args)
|
831
|
+
Map.add(*args)
|
832
|
+
end
|
833
|
+
|
834
|
+
def combine!(*args, &block)
|
835
|
+
add(*args, &block)
|
836
|
+
end
|
837
|
+
|
838
|
+
def combine(*args, &block)
|
839
|
+
dup.tap do |map|
|
840
|
+
map.combine!(*args, &block)
|
841
|
+
end
|
842
|
+
end
|
843
|
+
|
844
|
+
def leaf_for(key, options = {}, &block)
|
845
|
+
leaf = self
|
846
|
+
key = Array(key).flatten
|
847
|
+
k = alphanumeric_key_for(key.first)
|
775
848
|
|
776
|
-
|
849
|
+
key.each_cons(2) do |a, b|
|
777
850
|
a, b = alphanumeric_key_for(a), alphanumeric_key_for(b)
|
778
851
|
|
779
|
-
exists = collection_has_key?(
|
852
|
+
exists = collection_has_key?(leaf, a)
|
780
853
|
|
781
854
|
case b
|
782
855
|
when Numeric
|
783
856
|
if options[:autovivify]
|
784
|
-
|
857
|
+
leaf[a] = [] unless exists
|
858
|
+
end
|
859
|
+
|
860
|
+
case
|
861
|
+
when Array, Hash
|
862
|
+
nil
|
863
|
+
else
|
864
|
+
raise(IndexError, "(#{ leaf.inspect })[#{ a.inspect }][#{ b.inspect }]")
|
785
865
|
end
|
786
|
-
raise(IndexError, "(#{ collection.inspect })[#{ a.inspect }][#{ b.inspect }]") unless collection[a].is_a?(Array)
|
787
866
|
|
788
867
|
when String, Symbol
|
789
868
|
if options[:autovivify]
|
790
|
-
|
869
|
+
leaf[a] = Map.new unless exists
|
870
|
+
end
|
871
|
+
|
872
|
+
case
|
873
|
+
when Hash
|
874
|
+
nil
|
875
|
+
else
|
876
|
+
raise(IndexError, "(#{ leaf.inspect })[#{ a.inspect }][#{ b.inspect }]")
|
791
877
|
end
|
792
|
-
raise(IndexError, "(#{ collection.inspect })[#{ a.inspect }][#{ b.inspect }]") unless collection[a].is_a?(Map)
|
793
878
|
end
|
794
879
|
|
795
|
-
|
796
|
-
|
880
|
+
leaf = leaf[a]
|
881
|
+
k = b
|
797
882
|
end
|
798
883
|
|
799
|
-
leaf
|
800
|
-
|
801
|
-
block ? block.call(leaf, key) : [leaf, key]
|
884
|
+
block ? block.call(leaf, k) : [leaf, k]
|
802
885
|
end
|
803
886
|
|
804
887
|
def rm(*args)
|
data/map.gemspec
CHANGED
data/test/map_test.rb
CHANGED
@@ -343,14 +343,26 @@ Testing Map do
|
|
343
343
|
testing 'that maps support compound key/val setting' do
|
344
344
|
m = Map.new
|
345
345
|
assert{ m.set(:a, :b, :c, 42) }
|
346
|
-
assert{ m[:a][:b][:c] == 42 }
|
347
346
|
assert{ m.get(:a, :b, :c) == 42 }
|
347
|
+
|
348
|
+
m = Map.new
|
349
|
+
assert{ m.set([:a, :b, :c], 42) }
|
350
|
+
assert{ m.get(:a, :b, :c) == 42 }
|
351
|
+
|
352
|
+
m = Map.new
|
353
|
+
assert{ m.set([:a, :b, :c] => 42) }
|
354
|
+
assert{ m.get(:a, :b, :c) == 42 }
|
355
|
+
|
356
|
+
m = Map.new
|
348
357
|
assert{ m.set([:x, :y, :z] => 42.0, [:A, 2] => 'forty-two') }
|
349
358
|
assert{ m[:A].is_a?(Array) }
|
350
359
|
assert{ m[:A].size == 3}
|
351
360
|
assert{ m[:A][2] == 'forty-two' }
|
352
361
|
assert{ m[:x][:y].is_a?(Map) }
|
353
362
|
assert{ m[:x][:y][:z] == 42.0 }
|
363
|
+
|
364
|
+
assert{ Map.new.tap{|m| m.set} =~ {} }
|
365
|
+
assert{ Map.new.tap{|m| m.set({})} =~ {} }
|
354
366
|
end
|
355
367
|
|
356
368
|
testing 'that Map#get supports providing a default value in a block' do
|
@@ -393,6 +405,63 @@ Testing Map do
|
|
393
405
|
assert{ m[:key][0].is_a?(Map) }
|
394
406
|
end
|
395
407
|
|
408
|
+
testing 'that #add overlays the leaves of one hash onto another without nuking branches' do
|
409
|
+
m = Map.new
|
410
|
+
|
411
|
+
assert do
|
412
|
+
m.add(
|
413
|
+
:comments => [
|
414
|
+
{ :body => 'a' },
|
415
|
+
{ :body => 'b' },
|
416
|
+
],
|
417
|
+
|
418
|
+
[:comments, 0] => {'title' => 'teh title', 'description' => 'description'},
|
419
|
+
[:comments, 1] => {'description' => 'description'},
|
420
|
+
)
|
421
|
+
end
|
422
|
+
|
423
|
+
assert do
|
424
|
+
m =~
|
425
|
+
{"comments"=>
|
426
|
+
[{"body"=>"a", "title"=>"teh title", "description"=>"description"},
|
427
|
+
{"body"=>"b", "description"=>"description"}]}
|
428
|
+
end
|
429
|
+
|
430
|
+
m = Map.new
|
431
|
+
|
432
|
+
assert do
|
433
|
+
m.add(
|
434
|
+
[:a, :b, :c] => 42,
|
435
|
+
|
436
|
+
[:a, :b] => {:d => 42.0}
|
437
|
+
)
|
438
|
+
end
|
439
|
+
|
440
|
+
assert do
|
441
|
+
m =~
|
442
|
+
{"a"=>{"b"=>{"c"=>42, "d"=>42.0}}}
|
443
|
+
end
|
444
|
+
|
445
|
+
assert{ Map.new.tap{|m| m.add} =~ {} }
|
446
|
+
assert{ Map.new.tap{|m| m.add({})} =~ {} }
|
447
|
+
end
|
448
|
+
|
449
|
+
testing 'that Map.combine is teh sweet' do
|
450
|
+
{
|
451
|
+
[{:a => {:b => 42}}, {:a => {:c => 42.0}}] =>
|
452
|
+
{"a"=>{"b"=>42, "c"=>42.0}},
|
453
|
+
|
454
|
+
[{:a => {:b => 42}}, {:a => {:c => 42.0, :d => [1]}}] =>
|
455
|
+
{"a"=>{"b"=>42, "d"=>[1], "c"=>42.0}},
|
456
|
+
|
457
|
+
[{:a => {:b => 42}}, {:a => {:c => 42.0, :d => {0=>1}}}] =>
|
458
|
+
{"a"=>{"b"=>42, "d"=>{0=>1}, "c"=>42.0}}
|
459
|
+
|
460
|
+
}.each do |args, expected|
|
461
|
+
assert{ Map.combine(*args) =~ expected }
|
462
|
+
end
|
463
|
+
end
|
464
|
+
|
396
465
|
testing 'that maps support depth_first_each' do
|
397
466
|
m = Map.new
|
398
467
|
prefix = %w[ a b c ]
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: map
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.
|
4
|
+
version: 5.8.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-05-
|
12
|
+
date: 2012-05-22 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: ! 'description: map kicks the ass'
|
15
15
|
email: ara.t.howard@gmail.com
|
@@ -49,7 +49,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
49
49
|
version: '0'
|
50
50
|
requirements: []
|
51
51
|
rubyforge_project: codeforpeople
|
52
|
-
rubygems_version: 1.8.
|
52
|
+
rubygems_version: 1.8.24
|
53
53
|
signing_key:
|
54
54
|
specification_version: 3
|
55
55
|
summary: map
|