lib/map.rb in map-5.5.0 vs lib/map.rb in map-5.6.1

- old
+ new

@@ -1,8 +1,8 @@ # -*- encoding : utf-8 -*- class Map < Hash - Version = '5.5.0' unless defined?(Version) + Version = '5.6.1' unless defined?(Version) Load = Kernel.method(:load) unless defined?(Load) class << Map def version Map::Version @@ -719,12 +719,11 @@ def collection_has_key?(collection, key) case collection when Hash collection.has_key?(key) when Array - return false unless key - (0...collection.size).include?(Integer(key)) + (0...collection.size).include?((Integer(key) rescue -1)) end end def set(*args) if args.size == 1 and args.first.is_a?(Hash) @@ -734,49 +733,74 @@ value = args.pop keys = args spec[keys] = value end - spec.each do |keys, value| - keys = Array(keys).flatten + begin + spec.each do |keys, value| + keys = Array(keys).flatten + collection = self + key = keys.pop - collection = self + while((k = keys.shift)) do + k = alphanumeric_key_for(k) + collection = collection[k] + end - keys = key_for(keys) - - if keys.size <= 1 - key = keys.first collection[key] = value - next end + rescue + spec.each do |keys, value| + keys = Array(keys).flatten - key = nil + collection = self - keys.each_cons(2) do |a, b| - a, b = alphanumeric_key_for(a), alphanumeric_key_for(b) + if keys.size <= 1 + key = keys.first + collection[key] = value + next + end - exists = collection_has_key?(collection, a) + leaf_for(keys, :autovivify => true) do |leaf, key| + leaf[key] = value + end + end + end - case b - when Numeric - #collection[a] ||= [] + return spec.values + end + + def leaf_for(keys, options = {}, &block) + collection = self + key = nil + + keys.each_cons(2) do |a, b| + a, b = alphanumeric_key_for(a), alphanumeric_key_for(b) + + exists = collection_has_key?(collection, a) + + case b + when Numeric + if options[:autovivify] collection[a] = [] unless exists - raise(IndexError, "(#{ collection.inspect })[#{ a.inspect }]=#{ value.inspect }") unless collection[a].is_a?(Array) + end + raise(IndexError, "(#{ collection.inspect })[#{ a.inspect }][#{ b.inspect }]") unless collection[a].is_a?(Array) - when String, Symbol - #collection[a] ||= {} - collection[a] = {} unless exists - raise(IndexError, "(#{ collection.inspect })[#{ a.inspect }]=#{ value.inspect }") unless collection[a].is_a?(Hash) - end - collection = collection[a] - key = b + when String, Symbol + if options[:autovivify] + collection[a] = Map.new unless exists + end + raise(IndexError, "(#{ collection.inspect })[#{ a.inspect }][#{ b.inspect }]") unless collection[a].is_a?(Map) end - collection[key] = value + collection = collection[a] + key = b end - return spec.values + leaf = collection + + block ? block.call(leaf, key) : [leaf, key] end def rm(*args) paths, path = args.partition{|arg| arg.is_a?(Array)} paths.push(path) @@ -839,52 +863,15 @@ def alphanumeric_key_for(key) Map.alphanumeric_key_for(key) end -## key path support -# - def self.dot_key_for(*keys) - dot = keys.compact.flatten.join('.') - dot.split(%r/\s*[,.]\s*/).map{|part| part =~ %r/^\d+$/ ? Integer(part) : part} - end - - def self.dot_keys - @@dot_keys = {} unless defined?(@@dot_keys) - @@dot_keys - end - - def self.dot_keys? - ancestors.each do |ancestor| - return dot_keys[ancestor] if dot_keys.has_key?(ancestor) - end - false - end - - def dot_keys? - @dot_keys = false unless defined?(@dot_keys) - @dot_keys - end - - def self.dot_keys!(boolean = true) - dot_keys[self] = !!boolean - end - - def dot_keys!(boolean = true) - @dot_keys = !!boolean - end - def self.key_for(*keys) - return keys.flatten unless dot_keys? - self.dot_key_for(*keys) + return keys.flatten end def key_for(*keys) - if dot_keys? - self.class.dot_key_for(*keys) - else - self.class.key_for(*keys) - end + self.class.key_for(*keys) end ## TODO - technically this returns only leaves so the name isn't *quite* right. re-factor for 3.0 # def Map.depth_first_each(enumerable, path = [], accum = [], &block)