Class: MotionMap::Map

Inherits:
Hash
  • Object
show all
Defined in:
lib/motion-map/map.rb

Constant Summary collapse

Dup =
instance_method(:dup)

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*args, &block) ⇒ Map

Returns a new instance of Map.



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/motion-map/map.rb', line 101

def initialize(*args, &block)
  case args.size
    when 0
      super(&block)
    when 1
      first = args.first
      case first
        when nil, false
          nil
        when Hash             
          initialize_from_hash(first)
        when Array      
          initialize_from_array(first)
        else
          if first.respond_to?(:to_hash)
            initialize_from_hash(first.to_hash)
          else
            initialize_from_hash(first)
          end
      end        
    else
      initialize_from_array(args)
  end
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(*args, &block) ⇒ Object

a sane method missing that only supports writing values or reading *previously set* values



487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
# File 'lib/motion-map/map.rb', line 487

def method_missing(*args, &block)
  method = args.first.to_s
  case method
    when /=$/
      key = args.shift.to_s.chomp('=')
      value = args.shift
      self[key] = value
    when /\?$/
      key = args.shift.to_s.chomp('?')
      self.has?( key )
    else
      key = method
      unless has_key?(key)
        return(block ? fetch(key, &block) : super(*args))
      end
      self[key]
  end
end

Class Method Details

._explode(key, value, accum = {:branches => [], :leaves => []}) ⇒ Object



740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
# File 'lib/motion-map/map.rb', line 740

def self._explode(key, value, accum = {:branches => [], :leaves => []})
  key = Array(key).flatten

  case value
    when Array
      accum[:branches].push([key, Array])

      value.each_with_index do |v, k|
        MotionMap::Map._explode(key + [k], v, accum)
      end

    when Hash
      accum[:branches].push([key, MotionMap::Map])
      value.each do |k, v|
        MotionMap::Map._explode(key + [k], v, accum)
      end

    else
      accum[:leaves].push([key, value])
  end

  accum
end

.add(*args) ⇒ Object



764
765
766
767
768
769
770
771
# File 'lib/motion-map/map.rb', line 764

def self.add(*args)
  args.flatten!
  args.compact!

  MotionMap::Map.for(args.shift).tap do |map|
    args.each{|arg| map.add(arg)}
  end
end

.allocateObject



4
5
6
7
8
9
# File 'lib/motion-map/map.rb', line 4

def allocate
  super.instance_eval do
    @keys = []
    self
  end
end

.alphanumeric_key_for(key) ⇒ Object



869
870
871
872
873
874
875
# File 'lib/motion-map/map.rb', line 869

def self.alphanumeric_key_for(key)
  return key if key.is_a?(Numeric)

  digity, stringy, digits = %r/^(~)?(\d+)$/iomx.match(key).to_a

  digity ? stringy ? String(digits) : Integer(digits) : key
end

.blank?(value) ⇒ Boolean

Returns:

  • (Boolean)


577
578
579
580
581
582
583
584
585
586
587
588
589
590
# File 'lib/motion-map/map.rb', line 577

def self.blank?(value)
  return value.blank? if value.respond_to?(:blank?)

  case value
    when String
      value.strip.empty?
    when Numeric
      value == 0
    when false
      true
    else
      value.respond_to?(:empty?) ? value.empty? : !value
  end
end

.breadth_first_each(enumerable, accum = [], &block) ⇒ Object



942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
# File 'lib/motion-map/map.rb', line 942

def self.breadth_first_each(enumerable, accum = [], &block)
  levels = []

  keys = MotionMap::Map.depth_first_keys(enumerable)

  keys.each do |key|
    key.size.times do |i|
      k = key.slice(0, i + 1)
      level = k.size - 1
      levels[level] ||= Array.new
      last = levels[level].last
      levels[level].push(k) unless last == k
    end
  end

  levels.each do |level|
    level.each do |key|
      val = enumerable.get(key)
      block ? block.call(key, val) : accum.push([key, val])
    end
  end

  block ? enumerable : accum
end

.coerce(other) ⇒ Object



26
27
28
29
30
31
32
33
# File 'lib/motion-map/map.rb', line 26

def coerce(other)
  case other
    when MotionMap::Map
      other
    else
      allocate.update(other.to_hash)
  end
end

.collection_has?(collection, key, &block) ⇒ Boolean

Returns:

  • (Boolean)


619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
# File 'lib/motion-map/map.rb', line 619

def self.collection_has?(collection, key, &block)
  has_key =
    case collection
      when Array
        key = (Integer(key) rescue -1)
        (0...collection.size).include?(key)

      when Hash
        collection.has_key?(key)

      else
        raise(IndexError, "(#{ collection.inspect })[#{ key.inspect }]")
    end

  block.call(key) if(has_key and block)

  has_key
end

.collection_key(collection, key, &block) ⇒ Object



597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
# File 'lib/motion-map/map.rb', line 597

def self.collection_key(collection, key, &block)
  case collection
    when Array
      begin
        key = Integer(key)
      rescue
        raise(IndexError, "(#{ collection.inspect })[#{ key.inspect }]")
      end
      collection[key]

    when Hash
      collection[key]

    else
      raise(IndexError, "(#{ collection.inspect })[#{ key.inspect }]")
  end
end

.collection_set(collection, key, value, &block) ⇒ Object



642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
# File 'lib/motion-map/map.rb', line 642

def self.collection_set(collection, key, value, &block)
  set_key = false

  case collection
    when Array
      begin
        key = Integer(key)
      rescue
        raise(IndexError, "(#{ collection.inspect })[#{ key.inspect }]=#{ value.inspect }")
      end
      set_key = true
      collection[key] = value

    when Hash
      set_key = true
      collection[key] = value

    else
      raise(IndexError, "(#{ collection.inspect })[#{ key.inspect }]=#{ value.inspect }")
  end

  block.call(key) if(set_key and block)

  [key, value]
end

.combine(*args) ⇒ Object



773
774
775
# File 'lib/motion-map/map.rb', line 773

def self.combine(*args)
  MotionMap::Map.add(*args)
end

.convert_key(key) ⇒ Object



150
151
152
# File 'lib/motion-map/map.rb', line 150

def self.convert_key(key)
  key = key.kind_of?(Symbol) ? key.to_s : key
end

.convert_value(value) ⇒ Object



162
163
164
165
166
167
168
169
170
171
# File 'lib/motion-map/map.rb', line 162

def self.convert_value(value)
  case value
    when Hash
      coerce(value)
    when Array
      value = value.map{|v| convert_value(v)}
    else
      value
  end
end

.depth_first_each(enumerable, path = [], accum = [], &block) ⇒ Object

TODO - technically this returns only leaves so the name isn’t quite right. re-factor for 3.0



891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
# File 'lib/motion-map/map.rb', line 891

def self.depth_first_each(enumerable, path = [], accum = [], &block)
  self.pairs_for(enumerable) do |key, val|
    path.push(key)
    if((val.is_a?(Hash) or val.is_a?(Array)) and not val.empty?)
      MotionMap::Map.depth_first_each(val, path, accum)
    else
      accum << [path.dup, val]
    end
    path.pop()
  end
  if block
    accum.each{|keys, val| block.call(keys, val)}
  else
    accum
  end
end

.depth_first_keys(enumerable, path = [], accum = [], &block) ⇒ Object



908
909
910
911
912
# File 'lib/motion-map/map.rb', line 908

def self.depth_first_keys(enumerable, path = [], accum = [], &block)
  accum = self.depth_first_each(enumerable, path = [], accum = [], &block)
  accum.map!{|kv| kv.first}
  accum
end

.depth_first_values(enumerable, path = [], accum = [], &block) ⇒ Object



914
915
916
917
918
# File 'lib/motion-map/map.rb', line 914

def self.depth_first_values(enumerable, path = [], accum = [], &block)
  accum = self.depth_first_each(enumerable, path = [], accum = [], &block)
  accum.map!{|kv| kv.last}
  accum
end

.each_pair(*args, &block) ⇒ Object

iterate over arguments in pairs smartly.



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/motion-map/map.rb', line 37

def each_pair(*args, &block)
  size = args.size
  parity = size % 2 == 0 ? :even : :odd
  first = args.first

  if block.nil?
    result = []
    block = lambda{|*kv| result.push(kv)}
  else
    result = args
  end

  return args if size == 0

  if size == 1
    if first.respond_to?(:each_pair)
      first.each_pair do |key, val|
        block.call(key, val)
      end
      return args
    end

    if first.respond_to?(:each_slice)
      first.each_slice(2) do |key, val|
        block.call(key, val)
      end
      return args
    end
    raise(ArgumentError, 'odd number of arguments for Map')
  end

  array_of_pairs = args.all?{|a| a.is_a?(Array) and a.size == 2}

  if array_of_pairs
    args.each do |pair|
      key, val, *ignored = pair
      block.call(key, val)
    end
  else
    0.step(args.size - 1, 2) do |a|
      key = args[a]
      val = args[a + 1]
      block.call(key, val)
    end
  end

  args
end

.explode(hash) ⇒ Object



722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
# File 'lib/motion-map/map.rb', line 722

def self.explode(hash)
  accum = {:branches => [], :leaves => []}

  hash.each do |key, value|
    MotionMap::Map._explode(key, value, accum)
  end

  branches = accum[:branches]
  leaves = accum[:leaves]

  sort_by_key_size = proc{|a,b| a.first.size <=> b.first.size}

  branches.sort!(&sort_by_key_size)
  leaves.sort!(&sort_by_key_size)

  accum
end

.for(*args, &block) ⇒ Object



19
20
21
22
23
24
# File 'lib/motion-map/map.rb', line 19

def for(*args, &block)
  if(args.size == 1 and block.nil?)
    return args.first if args.first.class == self
  end
  new(*args, &block)
end

.from_hash(hash, order = nil) ⇒ Object

support for building ordered hasshes from a Map’s own image



424
425
426
427
428
# File 'lib/motion-map/map.rb', line 424

def self.from_hash(hash, order = nil)
  map = MotionMap::Map.for(hash)
  map.reorder!(order) if order
  map
end

.intersection(a, b) ⇒ Object



86
87
88
89
90
# File 'lib/motion-map/map.rb', line 86

def intersection(a, b)
  a, b, i = MotionMap::Map.for(a), MotionMap::Map.for(b), MotionMap::Map.new
  a.depth_first_each{|key, val| i.set(key, val) if b.has?(key)}
  i
end

.key_for(*keys) ⇒ Object



881
882
883
# File 'lib/motion-map/map.rb', line 881

def self.key_for(*keys)
  return keys.flatten
end

.keys_for(enumerable) ⇒ Object



967
968
969
# File 'lib/motion-map/map.rb', line 967

def self.keys_for(enumerable)
  keys = enumerable.respond_to?(:keys) ? enumerable.keys : Array.new(enumerable.size){|i| i}
end

.map_for(hash) ⇒ Object



141
142
143
144
145
# File 'lib/motion-map/map.rb', line 141

def self.map_for(hash)
  hash = klass.coerce(hash)
  hash.default = hash.default
  hash
end

.match(haystack, needle) ⇒ Object



92
93
94
# File 'lib/motion-map/map.rb', line 92

def match(haystack, needle)
  intersection(haystack, needle) == needle
end

.new(*args, &block) ⇒ Object Also known as: []



11
12
13
14
15
16
# File 'lib/motion-map/map.rb', line 11

def new(*args, &block)
  allocate.instance_eval do
    initialize(*args, &block)
    self
  end
end

.pairs_for(enumerable, *args, &block) ⇒ Object



920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
# File 'lib/motion-map/map.rb', line 920

def self.pairs_for(enumerable, *args, &block)
  if block.nil?
    pairs, block = [], lambda{|*pair| pairs.push(pair)}
  else
    pairs = false
  end

  result =
    case enumerable
      when Hash
        enumerable.each_pair(*args, &block)
      when Array
        enumerable.each_with_index(*args) do |val, key|
          block.call(key, val)
        end
      else
        enumerable.each_pair(*args, &block)
    end

  pairs ? pairs : result
end

Instance Method Details

#<=>(other) ⇒ Object



398
399
400
401
402
# File 'lib/motion-map/map.rb', line 398

def <=>(other)
  cmp = keys <=> klass.coerce(other).keys
  return cmp unless cmp.zero?
  values <=> klass.coerce(other).values
end

#==(other) ⇒ Object

equality / sorting / matching support



384
385
386
387
388
389
390
391
392
393
394
395
396
# File 'lib/motion-map/map.rb', line 384

def ==(other)
  case other
    when MotionMap::Map
      return false if keys != other.keys
      super(other)

    when Hash
      self == MotionMap::Map.from_hash(other, self)

    else
      false
  end
end

#=~(hash) ⇒ Object



404
405
406
# File 'lib/motion-map/map.rb', line 404

def =~(hash)
  to_hash == klass.coerce(hash).to_hash
end

#[](key) ⇒ Object



227
228
229
230
# File 'lib/motion-map/map.rb', line 227

def [](key)
  key = convert_key(key)
  __get__(key)
end

#[]=(key, val) ⇒ Object Also known as: store



220
221
222
223
224
# File 'lib/motion-map/map.rb', line 220

def []=(key, val)
  key, val = convert(key, val)
  keys.push(key) unless has_key?(key)
  __set__(key, val)
end

#__get__Object



217
# File 'lib/motion-map/map.rb', line 217

alias_method '__get__', '[]'

#__set__Object

writer/reader methods



216
# File 'lib/motion-map/map.rb', line 216

alias_method '__set__', '[]='

#__update__Object



218
# File 'lib/motion-map/map.rb', line 218

alias_method '__update__', 'update'

#add(*args) ⇒ Object



696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
# File 'lib/motion-map/map.rb', line 696

def add(*args)
  case
    when args.empty?
      return []
    when args.size == 1 && args.first.is_a?(Hash)
      hash = args.shift
    else
      hash = {}
      value = args.pop
      key = Array(args).flatten
      hash[key] = value
  end

  exploded = MotionMap::Map.explode(hash)

  exploded[:branches].each do |key, type|
    set(key, type.new) unless get(key).is_a?(type)
  end

  exploded[:leaves].each do |key, value|
    set(key, value)
  end

  self
end

#alphanumeric_key_for(key) ⇒ Object



877
878
879
# File 'lib/motion-map/map.rb', line 877

def alphanumeric_key_for(key)
  MotionMap::Map.alphanumeric_key_for(key)
end

#apply(other) ⇒ Object



862
863
864
865
866
867
# File 'lib/motion-map/map.rb', line 862

def apply(other)
  MotionMap::Map.for(other).depth_first_each do |keys, value|
    set(keys => value) unless !get(keys).nil?
  end
  self
end

#blank?(*keys) ⇒ Boolean

Returns:

  • (Boolean)


592
593
594
595
# File 'lib/motion-map/map.rb', line 592

def blank?(*keys)
  return empty? if keys.empty?
  !has?(*keys) or MotionMap::Map.blank?(get(*keys))
end

#breadth_first_each(*args, &block) ⇒ Object



983
984
985
# File 'lib/motion-map/map.rb', line 983

def breadth_first_each(*args, &block)
  MotionMap::Map.breadth_first_each(enumerable=self, *args, &block)
end

#clearObject



315
316
317
318
# File 'lib/motion-map/map.rb', line 315

def clear
  keys.clear
  super
end

#cloneObject



202
203
204
# File 'lib/motion-map/map.rb', line 202

def clone
  copy
end

#collection_has?(*args, &block) ⇒ Boolean

Returns:

  • (Boolean)


638
639
640
# File 'lib/motion-map/map.rb', line 638

def collection_has?(*args, &block)
  MotionMap::Map.collection_has?(*args, &block)
end

#collection_key(*args, &block) ⇒ Object



615
616
617
# File 'lib/motion-map/map.rb', line 615

def collection_key(*args, &block)
  MotionMap::Map.collection_key(*args, &block)
end

#collection_set(*args, &block) ⇒ Object



668
669
670
# File 'lib/motion-map/map.rb', line 668

def collection_set(*args, &block)
  MotionMap::Map.collection_set(*args, &block)
end

#combine(*args, &block) ⇒ Object



781
782
783
784
785
# File 'lib/motion-map/map.rb', line 781

def combine(*args, &block)
  dup.tap do |map|
    map.combine!(*args, &block)
  end
end

#combine!(*args, &block) ⇒ Object



777
778
779
# File 'lib/motion-map/map.rb', line 777

def combine!(*args, &block)
  add(*args, &block)
end

#convert(key, val) ⇒ Object



182
183
184
# File 'lib/motion-map/map.rb', line 182

def convert(key, val)
  [convert_key(key), convert_value(val)]
end

#convert_key(key) ⇒ Object



154
155
156
157
158
159
160
# File 'lib/motion-map/map.rb', line 154

def convert_key(key)
  if klass.respond_to?(:convert_key)
    klass.convert_key(key)
  else
    MotionMap::Map.convert_key(key)
  end
end

#convert_value(value) ⇒ Object Also known as: convert_val



172
173
174
175
176
177
178
# File 'lib/motion-map/map.rb', line 172

def convert_value(value)
  if klass.respond_to?(:convert_value)
    klass.convert_value(value)
  else
    MotionMap::Map.convert_value(value)
  end
end

#copyObject



186
187
188
189
190
191
192
193
194
# File 'lib/motion-map/map.rb', line 186

def copy
  default = self.default
  self.default = nil
  copy = Marshal.load(Marshal.dump(self)) rescue Dup.bind(self).call()
  copy.default = default
  copy
ensure
  self.default = default
end

#default(key = nil) ⇒ Object



206
207
208
# File 'lib/motion-map/map.rb', line 206

def default(key = nil)
  key.is_a?(Symbol) && include?(key = key.to_s) ? self[key] : super
end

#default=(value) ⇒ Object

Raises:

  • (ArgumentError)


210
211
212
# File 'lib/motion-map/map.rb', line 210

def default=(value)
  raise ArgumentError.new("Map doesn't work so well with a non-nil default value!") unless value.nil?
end

#delete(key) ⇒ Object

mutators



309
310
311
312
313
# File 'lib/motion-map/map.rb', line 309

def delete(key)
  key = convert_key(key)
  keys.delete(key)
  super(key)
end

#delete_ifObject



320
321
322
323
324
325
# File 'lib/motion-map/map.rb', line 320

def delete_if
  to_delete = []
  keys.each{|key| to_delete.push(key) if yield(key,self[key])}
  to_delete.each{|key| delete(key)}
  self
end

#depth_first_each(*args, &block) ⇒ Object



971
972
973
# File 'lib/motion-map/map.rb', line 971

def depth_first_each(*args, &block)
  MotionMap::Map.depth_first_each(enumerable=self, *args, &block)
end

#depth_first_keys(*args, &block) ⇒ Object



975
976
977
# File 'lib/motion-map/map.rb', line 975

def depth_first_keys(*args, &block)
  MotionMap::Map.depth_first_keys(enumerable=self, *args, &block)
end

#depth_first_values(*args, &block) ⇒ Object



979
980
981
# File 'lib/motion-map/map.rb', line 979

def depth_first_values(*args, &block)
  MotionMap::Map.depth_first_values(enumerable=self, *args, &block)
end

#dupObject



198
199
200
# File 'lib/motion-map/map.rb', line 198

def dup
  copy
end

#eachObject Also known as: each_pair



301
302
303
304
# File 'lib/motion-map/map.rb', line 301

def each
  keys.each{|key| yield(key, self[key])}
  self
end

#each_keyObject



291
292
293
294
# File 'lib/motion-map/map.rb', line 291

def each_key
  keys.each{|key| yield(key)}
  self
end

#each_valueObject



296
297
298
299
# File 'lib/motion-map/map.rb', line 296

def each_value
  keys.each{|key| yield self[key]}
  self
end

#each_with_indexObject

iterator methods



286
287
288
289
# File 'lib/motion-map/map.rb', line 286

def each_with_index
  keys.each_with_index{|key, index| yield([key, self[key]], index)}
  self
end

#fetch(key, *args, &block) ⇒ Object



232
233
234
235
# File 'lib/motion-map/map.rb', line 232

def fetch(key, *args, &block)
  key = convert_key(key)
  super(key, *args, &block)
end

#firstObject



276
277
278
# File 'lib/motion-map/map.rb', line 276

def first
  [keys.first, self[keys.first]]
end

#forcing(forcing = nil, &block) ⇒ Object



841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
# File 'lib/motion-map/map.rb', line 841

def forcing(forcing=nil, &block)
  @forcing ||= nil

  if block
    begin
      previous = @forcing
      @forcing = forcing
      block.call()
    ensure
      @forcing = previous
    end
  else
    @forcing
  end
end

#forcing?(forcing = nil) ⇒ Boolean

Returns:

  • (Boolean)


857
858
859
860
# File 'lib/motion-map/map.rb', line 857

def forcing?(forcing=nil)
  @forcing ||= nil
  @forcing == forcing
end

#get(*keys) ⇒ Object

support for compound key indexing and depth first iteration



520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
# File 'lib/motion-map/map.rb', line 520

def get(*keys)
  keys = key_for(keys)

  if keys.size <= 1
    if !self.has_key?(keys.first) && block_given?
      return yield
    else
      return self[keys.first]
    end
  end

  keys, key = keys[0..-2], keys[-1]
  collection = self

  keys.each do |k|
    if MotionMap::Map.collection_has?(collection, k)
      collection = MotionMap::Map.collection_key(collection, k)
    else
      collection = nil
    end

    unless collection.respond_to?('[]')
      leaf = collection
      return leaf
    end
  end

  if !MotionMap::Map.collection_has?(collection, key) && block_given?
    default_value = yield
  else
    MotionMap::Map.collection_key(collection, key)
  end
end

#has?(*keys) ⇒ Boolean

Returns:

  • (Boolean)


554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
# File 'lib/motion-map/map.rb', line 554

def has?(*keys)
  keys = key_for(keys)
  collection = self

  return MotionMap::Map.collection_has?(collection, keys.first) if keys.size <= 1

  keys, key = keys[0..-2], keys[-1]

  keys.each do |k|
    if MotionMap::Map.collection_has?(collection, k)
      collection = MotionMap::Map.collection_key(collection, k)
    else
      collection = nil
    end

    return collection unless collection.respond_to?('[]')
  end

  return false unless(collection.is_a?(Hash) or collection.is_a?(Array))

  MotionMap::Map.collection_has?(collection, key)
end

#idObject

Raises:

  • (NoMethodError)


512
513
514
515
516
# File 'lib/motion-map/map.rb', line 512

def id
  return self[:id] if has_key?(:id)
  return self[:_id] if has_key?(:_id)
  raise NoMethodError
end

#initialize_from_array(array) ⇒ Object



132
133
134
135
# File 'lib/motion-map/map.rb', line 132

def initialize_from_array(array)
  map = self    
  MotionMap::Map.each_pair(array){|key, val| map[key] = val}
end

#initialize_from_hash(hash) ⇒ Object



126
127
128
129
130
# File 'lib/motion-map/map.rb', line 126

def initialize_from_hash(hash)
  map = self
  map.update(hash)
  map.default = hash.default
end

#inspect(*args, &block) ⇒ Object



452
453
454
# File 'lib/motion-map/map.rb', line 452

def inspect(*args, &block)
  super.inspect
end

#invertObject



430
431
432
433
434
435
# File 'lib/motion-map/map.rb', line 430

def invert
  inverted = klass.allocate
  inverted.default = self.default
  keys.each{|key| inverted[self[key]] = key }
  inverted
end

#keep_if(&block) ⇒ Object

Raises:

  • (RuntimeError)


328
329
330
331
332
333
# File 'lib/motion-map/map.rb', line 328

def keep_if( &block )
  raise RuntimeError.new( "can't modify frozen #{ self.class.name }" ) if frozen?
  return to_enum( :keep_if ) unless block_given?
  each { | key , val | delete key unless yield( key , val ) }
  self
end

#key?(key) ⇒ Boolean Also known as: include?, has_key?, member?

Returns:

  • (Boolean)


237
238
239
# File 'lib/motion-map/map.rb', line 237

def key?(key)
  super(convert_key(key))
end

#key_for(*keys) ⇒ Object



885
886
887
# File 'lib/motion-map/map.rb', line 885

def key_for(*keys)
  self.class.key_for(*keys)
end

#keysObject



97
98
99
# File 'lib/motion-map/map.rb', line 97

def keys
  @keys ||= []
end

#klassObject



137
138
139
# File 'lib/motion-map/map.rb', line 137

def klass
  self.class
end

#lastObject



280
281
282
# File 'lib/motion-map/map.rb', line 280

def last
  [keys.last, self[keys.last]]
end

#leaf_for(key, options = {}, &block) ⇒ Object



787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
# File 'lib/motion-map/map.rb', line 787

def leaf_for(key, options = {}, &block)
  leaf = self
  key = Array(key).flatten
  k = key.first

  key.each_cons(2) do |a, b|
    exists = MotionMap::Map.collection_has?(leaf, a)

    case b
      when Numeric
        if options[:autovivify]
          MotionMap::Map.collection_set(leaf, a, Array.new) unless exists
        end

      when String, Symbol
        if options[:autovivify]
          MotionMap::Map.collection_set(leaf, a, MotionMap::Map.new) unless exists
        end
    end

    leaf = MotionMap::Map.collection_key(leaf, a)
    k = b
  end

  block ? block.call(leaf, k) : [leaf, k]
end

#map_for(hash) ⇒ Object



146
147
148
# File 'lib/motion-map/map.rb', line 146

def map_for(hash)
  klass.map_for(hash)
end

#merge(*args) ⇒ Object Also known as: +



250
251
252
# File 'lib/motion-map/map.rb', line 250

def merge(*args)
  copy.update(*args)
end

#popObject



374
375
376
377
378
379
380
# File 'lib/motion-map/map.rb', line 374

def pop
  unless empty?
    key = keys.last
    val = delete(key)
    [key, val]
  end
end

#push(*args) ⇒ Object



362
363
364
365
366
367
368
369
370
371
372
# File 'lib/motion-map/map.rb', line 362

def push(*args)
  MotionMap::Map.each_pair(*args) do |key, val|
    if key?(key)
      delete(key)
    else
      keys.push(key)
    end
    __set__(key, val)
  end
  self
end

#reject(&block) ⇒ Object



437
438
439
# File 'lib/motion-map/map.rb', line 437

def reject(&block)
  dup.delete_if(&block)
end

#reject!(&block) ⇒ Object



441
442
443
444
# File 'lib/motion-map/map.rb', line 441

def reject!(&block)
  hash = reject(&block)
  self == hash ? nil : hash
end

#reorder(order = {}) ⇒ Object

reordering support



410
411
412
413
414
415
416
# File 'lib/motion-map/map.rb', line 410

def reorder(order = {})
  order = MotionMap::Map.for(order)
  map = MotionMap::Map.new
  keys = order.depth_first_keys | depth_first_keys
  keys.each{|key| map.set(key, get(key))}
  map
end

#reorder!(order = {}) ⇒ Object



418
419
420
# File 'lib/motion-map/map.rb', line 418

def reorder!(order = {})
  replace(reorder(order))
end

#replace(*args) ⇒ Object



335
336
337
338
# File 'lib/motion-map/map.rb', line 335

def replace(*args)
  clear
  update(*args)
end

#respond_to?(method, *args, &block) ⇒ Boolean

Returns:

  • (Boolean)


506
507
508
509
510
# File 'lib/motion-map/map.rb', line 506

def respond_to?(method, *args, &block)
  has_key = has_key?(method)
  setter = method.to_s =~ /=\Z/o
  !!((!has_key and setter) or has_key or super)
end

#reverse_merge(hash) ⇒ Object



255
256
257
258
259
# File 'lib/motion-map/map.rb', line 255

def reverse_merge(hash)
  map = copy
  map.each{|key, val| MotionMap::Map[key] = val unless MotionMap::Map.key?(key)}
  map
end

#reverse_merge!(hash) ⇒ Object



261
262
263
# File 'lib/motion-map/map.rb', line 261

def reverse_merge!(hash)
  replace(reverse_merge(hash))
end

#rm(*args) ⇒ Object



814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
# File 'lib/motion-map/map.rb', line 814

def rm(*args)
  paths, path = args.partition{|arg| arg.is_a?(Array)}
  paths.push(path)

  paths.each do |path|
    if path.size == 1
      delete(*path)
      next
    end

    branch, leaf = path[0..-2], path[-1]
    collection = get(branch)

    case collection
      when Hash
        key = leaf
        collection.delete(key)
      when Array
        index = leaf
        collection.delete_at(index)
      else
        raise(IndexError, "(#{ collection.inspect }).rm(#{ path.inspect })")
    end
  end
  paths
end

#selectObject



446
447
448
449
450
# File 'lib/motion-map/map.rb', line 446

def select
  array = []
  each{|key, val| array << [key,val] if yield(key, val)}
  array
end

#set(*args) ⇒ Object



672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
# File 'lib/motion-map/map.rb', line 672

def set(*args)
  case
    when args.empty?
      return []
    when args.size == 1 && args.first.is_a?(Hash)
      hash = args.shift
    else
      hash = {}
      value = args.pop
      key = Array(args).flatten
      hash[key] = value
  end

  strategy = hash.map{|key, value| [Array(key), value]}

  strategy.each do |key, value|
    leaf_for(key, :autovivify => true) do |leaf, k|
      MotionMap::Map.collection_set(leaf, k, value)
    end
  end

  self
end

#shiftObject

ordered container specific methods



342
343
344
345
346
347
348
# File 'lib/motion-map/map.rb', line 342

def shift
  unless empty?
    key = keys.first
    val = delete(key)
    [key, val]
  end
end

#to_arrayObject Also known as: to_a



465
466
467
468
469
# File 'lib/motion-map/map.rb', line 465

def to_array
  array = []
  each{|*pair| array.push(pair)}
  array
end

#to_hashObject



456
457
458
459
460
461
462
463
# File 'lib/motion-map/map.rb', line 456

def to_hash
  hash = Hash.new(default)
  each do |key, val|
    val = val.to_hash if val.respond_to?(:to_hash)
    hash[key] = val
  end
  hash
end

#to_listObject



472
473
474
475
476
477
478
# File 'lib/motion-map/map.rb', line 472

def to_list
  list = []
  each_pair do |key, val|
    list[key.to_i] = val if(key.is_a?(Numeric) or key.to_s =~ %r/^\d+$/)
  end
  list
end

#to_sObject



480
481
482
# File 'lib/motion-map/map.rb', line 480

def to_s
  to_array.to_s
end

#unshift(*args) ⇒ Object



350
351
352
353
354
355
356
357
358
359
360
# File 'lib/motion-map/map.rb', line 350

def unshift(*args)
  MotionMap::Map.each_pair(*args) do |key, val|
    if key?(key)
      delete(key)
    else
      keys.unshift(key)
    end
    __set__(key, val)
  end
  self
end

#update(*args) ⇒ Object Also known as: merge!



244
245
246
247
# File 'lib/motion-map/map.rb', line 244

def update(*args)
  MotionMap::Map.each_pair(*args){|key, val| store(key, val)}
  self
end

#valuesObject Also known as: vals



265
266
267
268
269
# File 'lib/motion-map/map.rb', line 265

def values
  array = []
  keys.each{|key| array.push(self[key])}
  array
end

#values_at(*keys) ⇒ Object



272
273
274
# File 'lib/motion-map/map.rb', line 272

def values_at(*keys)
  keys.map{|key| self[key]}
end