map 2.7.1 → 2.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/TODO +3 -0
- data/lib/map.rb +112 -9
- data/map.gemspec +1 -1
- data/test/map_test.rb +59 -0
- metadata +5 -5
data/TODO
CHANGED
data/lib/map.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
class Map < Hash
|
2
|
-
Version = '2.
|
2
|
+
Version = '2.8.0' unless defined?(Version)
|
3
3
|
Load = Kernel.method(:load) unless defined?(Load)
|
4
4
|
|
5
5
|
class << Map
|
@@ -145,8 +145,17 @@ class Map < Hash
|
|
145
145
|
|
146
146
|
args
|
147
147
|
end
|
148
|
-
|
149
148
|
alias_method '[]', 'new'
|
149
|
+
|
150
|
+
def intersection(a, b)
|
151
|
+
a, b, i = Map.for(a), Map.for(b), Map.new
|
152
|
+
a.depth_first_each{|key, val| i.set(key, val) if b.has?(key)}
|
153
|
+
i
|
154
|
+
end
|
155
|
+
|
156
|
+
def match(haystack, needle)
|
157
|
+
intersection(haystack, needle) == needle
|
158
|
+
end
|
150
159
|
end
|
151
160
|
|
152
161
|
unless defined?(Dynamic)
|
@@ -443,22 +452,54 @@ class Map < Hash
|
|
443
452
|
end
|
444
453
|
end
|
445
454
|
|
446
|
-
#
|
455
|
+
# equality / sorting / matching support
|
447
456
|
#
|
448
|
-
def ==(
|
449
|
-
|
450
|
-
|
451
|
-
|
457
|
+
def ==(other)
|
458
|
+
case other
|
459
|
+
when Map
|
460
|
+
return false if keys != other.keys
|
461
|
+
super(other)
|
462
|
+
|
463
|
+
when Hash
|
464
|
+
self == Map.from_hash(other, self)
|
465
|
+
|
466
|
+
else
|
467
|
+
false
|
468
|
+
end
|
452
469
|
end
|
453
470
|
|
454
471
|
def <=>(other)
|
455
|
-
keys <=> klass.coerce(other).keys
|
472
|
+
cmp = keys <=> klass.coerce(other).keys
|
473
|
+
return cmp unless cmp.zero?
|
474
|
+
values <=> klass.coerce(other).values
|
456
475
|
end
|
457
476
|
|
458
477
|
def =~(hash)
|
459
478
|
to_hash == klass.coerce(hash).to_hash
|
460
479
|
end
|
461
480
|
|
481
|
+
# reordering support
|
482
|
+
#
|
483
|
+
def reorder(order = {})
|
484
|
+
order = Map.for(order)
|
485
|
+
map = Map.new
|
486
|
+
keys = order.depth_first_keys | depth_first_keys
|
487
|
+
keys.each{|key| map.set(key, get(key))}
|
488
|
+
map
|
489
|
+
end
|
490
|
+
|
491
|
+
def reorder!(order = {})
|
492
|
+
replace(reorder(order))
|
493
|
+
end
|
494
|
+
|
495
|
+
# support for building ordered hasshes from a map's own image
|
496
|
+
#
|
497
|
+
def Map.from_hash(hash, order = nil)
|
498
|
+
map = Map.for(hash)
|
499
|
+
map.reorder!(order) if order
|
500
|
+
map
|
501
|
+
end
|
502
|
+
|
462
503
|
def invert
|
463
504
|
inverted = klass.allocate
|
464
505
|
inverted.default = self.default
|
@@ -697,6 +738,8 @@ class Map < Hash
|
|
697
738
|
Map.alphanumeric_key_for(key)
|
698
739
|
end
|
699
740
|
|
741
|
+
## TODO - technically this returns only leaves so the name isn't *quite* right. re-factor for 3.0
|
742
|
+
#
|
700
743
|
def Map.depth_first_each(enumerable, path = [], accum = [], &block)
|
701
744
|
Map.pairs_for(enumerable) do |key, val|
|
702
745
|
path.push(key)
|
@@ -710,10 +753,22 @@ class Map < Hash
|
|
710
753
|
if block
|
711
754
|
accum.each{|keys, val| block.call(keys, val)}
|
712
755
|
else
|
713
|
-
|
756
|
+
accum
|
714
757
|
end
|
715
758
|
end
|
716
759
|
|
760
|
+
def Map.depth_first_keys(enumerable, path = [], accum = [], &block)
|
761
|
+
accum = Map.depth_first_each(enumerable, path = [], accum = [], &block)
|
762
|
+
accum.map!{|kv| kv.first}
|
763
|
+
accum
|
764
|
+
end
|
765
|
+
|
766
|
+
def Map.depth_first_values(enumerable, path = [], accum = [], &block)
|
767
|
+
accum = Map.depth_first_each(enumerable, path = [], accum = [], &block)
|
768
|
+
accum.map!{|kv| kv.last}
|
769
|
+
accum
|
770
|
+
end
|
771
|
+
|
717
772
|
def Map.pairs_for(enumerable, *args, &block)
|
718
773
|
if block.nil?
|
719
774
|
pairs, block = [], lambda{|*pair| pairs.push(pair)}
|
@@ -736,9 +791,57 @@ class Map < Hash
|
|
736
791
|
pairs ? pairs : result
|
737
792
|
end
|
738
793
|
|
794
|
+
def Map.breadth_first_each(enumerable, accum = [], &block)
|
795
|
+
levels = []
|
796
|
+
|
797
|
+
keys = Map.depth_first_keys(enumerable)
|
798
|
+
|
799
|
+
keys.each do |key|
|
800
|
+
key.size.times do |i|
|
801
|
+
k = key.slice(0, i + 1)
|
802
|
+
level = k.size - 1
|
803
|
+
levels[level] ||= Array.new
|
804
|
+
last = levels[level].last
|
805
|
+
levels[level].push(k) unless last == k
|
806
|
+
end
|
807
|
+
end
|
808
|
+
|
809
|
+
levels.each do |level|
|
810
|
+
level.each do |key|
|
811
|
+
val = enumerable.get(key)
|
812
|
+
block ? block.call(key, val) : accum.push([key, val])
|
813
|
+
end
|
814
|
+
end
|
815
|
+
|
816
|
+
block ? enumerable : accum
|
817
|
+
end
|
818
|
+
|
819
|
+
def Map.keys_for(enumerable)
|
820
|
+
keys = enumerable.respond_to?(:keys) ? enumerable.keys : Array.new(enumerable.size){|i| i}
|
821
|
+
end
|
822
|
+
|
739
823
|
def depth_first_each(*args, &block)
|
740
824
|
Map.depth_first_each(enumerable=self, *args, &block)
|
741
825
|
end
|
826
|
+
|
827
|
+
def depth_first_keys(*args, &block)
|
828
|
+
Map.depth_first_keys(enumerable=self, *args, &block)
|
829
|
+
end
|
830
|
+
|
831
|
+
def depth_first_values(*args, &block)
|
832
|
+
Map.depth_first_values(enumerable=self, *args, &block)
|
833
|
+
end
|
834
|
+
|
835
|
+
def breadth_first_each(*args, &block)
|
836
|
+
Map.breadth_first_each(enumerable=self, *args, &block)
|
837
|
+
end
|
838
|
+
|
839
|
+
def contains(other)
|
840
|
+
other = other.is_a?(Hash) ? Map.coerce(other) : other
|
841
|
+
breadth_first_each{|key, value| return true if value == other}
|
842
|
+
return false
|
843
|
+
end
|
844
|
+
alias_method 'contains?', 'contains'
|
742
845
|
end
|
743
846
|
|
744
847
|
module Kernel
|
data/map.gemspec
CHANGED
data/test/map_test.rb
CHANGED
@@ -371,6 +371,65 @@ Testing Map do
|
|
371
371
|
assert{ each_pair = ['a', 'b', 'c', nil] }
|
372
372
|
end
|
373
373
|
|
374
|
+
testing 'that maps support breath_first_each' do
|
375
|
+
map = Map[
|
376
|
+
'hash' , {'x' => 'y'},
|
377
|
+
'nested hash' , {'nested' => {'a' => 'b'}},
|
378
|
+
'array' , [0, 1, 2],
|
379
|
+
'nested array' , [[3], [4], [5]],
|
380
|
+
'string' , '42'
|
381
|
+
]
|
382
|
+
|
383
|
+
accum = []
|
384
|
+
Map.breadth_first_each(map){|k, v| accum.push([k, v])}
|
385
|
+
expected =
|
386
|
+
[[["hash"], {"x"=>"y"}],
|
387
|
+
[["nested hash"], {"nested"=>{"a"=>"b"}}],
|
388
|
+
[["array"], [0, 1, 2]],
|
389
|
+
[["nested array"], [[3], [4], [5]]],
|
390
|
+
[["string"], "42"],
|
391
|
+
[["hash", "x"], "y"],
|
392
|
+
[["nested hash", "nested"], {"a"=>"b"}],
|
393
|
+
[["array", 0], 0],
|
394
|
+
[["array", 1], 1],
|
395
|
+
[["array", 2], 2],
|
396
|
+
[["nested array", 0], [3]],
|
397
|
+
[["nested array", 1], [4]],
|
398
|
+
[["nested array", 2], [5]],
|
399
|
+
[["nested hash", "nested", "a"], "b"],
|
400
|
+
[["nested array", 0, 0], 3],
|
401
|
+
[["nested array", 1, 0], 4],
|
402
|
+
[["nested array", 2, 0], 5]]
|
403
|
+
end
|
404
|
+
|
405
|
+
testing 'that maps have a needle-in-a-haystack like #contains? method' do
|
406
|
+
haystack = Map[
|
407
|
+
'hash' , {'x' => 'y'},
|
408
|
+
'nested hash' , {'nested' => {'a' => 'b'}},
|
409
|
+
'array' , [0, 1, 2],
|
410
|
+
'nested array' , [[3], [4], [5]],
|
411
|
+
'string' , '42'
|
412
|
+
]
|
413
|
+
|
414
|
+
needles = [
|
415
|
+
{'x' => 'y'},
|
416
|
+
{'nested' => {'a' => 'b'}},
|
417
|
+
{'a' => 'b'},
|
418
|
+
[0,1,2],
|
419
|
+
[[3], [4], [5]],
|
420
|
+
[3],
|
421
|
+
[4],
|
422
|
+
[5],
|
423
|
+
'42',
|
424
|
+
0,1,2,
|
425
|
+
3,4,5
|
426
|
+
]
|
427
|
+
|
428
|
+
needles.each do |needle|
|
429
|
+
assert{ haystack.contains?(needle) }
|
430
|
+
end
|
431
|
+
end
|
432
|
+
|
374
433
|
testing 'that #update and #replace accept map-ish objects' do
|
375
434
|
o = Object.new
|
376
435
|
def o.to_map() {:k => :v} end
|
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: 47
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 2
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 2.
|
8
|
+
- 8
|
9
|
+
- 0
|
10
|
+
version: 2.8.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-04-08 00:00:00 -06:00
|
19
19
|
default_executable:
|
20
20
|
dependencies: []
|
21
21
|
|