map 5.6.1 → 5.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. data/a.rb +41 -5
  2. data/lib/map.rb +128 -45
  3. data/map.gemspec +1 -1
  4. data/test/map_test.rb +70 -1
  5. 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.set(:a, :b, :c, 42)
11
- p m.get(:a, :b, 0)
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.set(:a, 0, 42)
17
- p m.get(:a, :b, 0)
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.6.1' unless defined?(Version)
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
- if args.size == 1 and args.first.is_a?(Hash)
730
- spec = args.shift
731
- else
732
- spec = {}
733
- value = args.pop
734
- keys = args
735
- spec[keys] = value
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
- begin
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
- collection[key] = value
743
+ strategy.each do |key, value|
744
+ leaf_for(key, :autovivify => true) do |leaf, k|
745
+ leaf[k] = value
750
746
  end
751
- rescue
752
- spec.each do |keys, value|
753
- keys = Array(keys).flatten
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
- collection = self
796
+ def Map._explode(key, value, accum = {:branches => [], :leaves => []})
797
+ key = Array(key).flatten
756
798
 
757
- if keys.size <= 1
758
- key = keys.first
759
- collection[key] = value
760
- next
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
- leaf_for(keys, :autovivify => true) do |leaf, key|
764
- leaf[key] = value
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
- end
813
+
814
+ else
815
+ accum[:leaves].push([key, value])
767
816
  end
768
817
 
769
- return spec.values
818
+ accum
770
819
  end
771
820
 
772
- def leaf_for(keys, options = {}, &block)
773
- collection = self
774
- key = nil
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
- keys.each_cons(2) do |a, b|
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?(collection, a)
852
+ exists = collection_has_key?(leaf, a)
780
853
 
781
854
  case b
782
855
  when Numeric
783
856
  if options[:autovivify]
784
- collection[a] = [] unless exists
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
- collection[a] = Map.new unless exists
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
- collection = collection[a]
796
- key = b
880
+ leaf = leaf[a]
881
+ k = b
797
882
  end
798
883
 
799
- leaf = collection
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)
@@ -3,7 +3,7 @@
3
3
 
4
4
  Gem::Specification::new do |spec|
5
5
  spec.name = "map"
6
- spec.version = "5.6.1"
6
+ spec.version = "5.8.0"
7
7
  spec.platform = Gem::Platform::RUBY
8
8
  spec.summary = "map"
9
9
  spec.description = "description: map kicks the ass"
@@ -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.6.1
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-18 00:00:00.000000000 Z
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.11
52
+ rubygems_version: 1.8.24
53
53
  signing_key:
54
54
  specification_version: 3
55
55
  summary: map