NAME map.rb
SYNOPSIS the awesome ruby container you've always wanted: a string/symbol indifferent ordered hash that works in all rubies
maps are bitchin ordered hashes that are both ordered, string/symbol
indifferent, and have all sorts of sweetness like recursive conversion, more
robust implementation than HashWithIndifferentAccess, support for struct
like (map.foo) access, and support for option/keyword access which avoids
several nasty classes of errors in many ruby libraries
INSTALL gem install map
URI http://github.com/ahoward/map
DESCRIPTION
maps are always ordered. constructing them in an ordered fashion builds
them that way, although the normal hash contructor is also supported
m = Map[:k, :v, :key, :val] m = Map(:k, :v, :key, :val) m = Map.new(:k, :v, :key, :val)
m = Map[[:k, :v], [:key, :val]]
m = Map(:k => :v, :key => :val) # ruh-oh, the input hash loses order!
m = Map.new(:k => :v, :key => :val) # ruh-oh, the input hash loses order!
m = Map.new
m[:a] = 0
m[:b] = 1
m[:c] = 2
p m.keys #=> ['a','b','c'] ### always ordered!
p m.values #=> [0,1,2] ### always ordered!
maps don't care about symbol vs.string keys
even via deep nesting
p m['bar'][:baz] #=> 42
many functions operate in a way one would expect from an ordered container
m.update(:k2 => :v2) m.update(:k2, :v2)
key_val_pair = m.shift
key_val_pair = m.pop
maps keep mapiness for even deep operations
m.update :nested => => {:are => :converted}
maps can give back clever little struct objects
m = Map(:foo => => 42) s = m.struct p s.foo.bar #=> 42
because option parsing is such a common use case for needing string/symbol
indifference map.rb comes out of the box loaded with option support
def foo(*args, &block) opts = Map.options(args) a = opts.getopt(:a) b = opts.getopt(:b, :default => false) end
opts = Map.(:a => 42, :b => nil, :c => false)
opts.getopt(:a) #=> 42
opts.getopt(:b) #=> nil
opts.getopt(:b, :default => 42) #=> 42
opts.getopt(:c) #=> false
opts.getopt(:d, :default => false) #=> false
this avoids such bugs as
options = => false read_only = options || true # should be false but is true
with options this becomes
options = Map.options(:read_only => true) read_only = options.getopt(:read_only, :default => false) #=> true
maps support some really nice operators that hashes/orderedhashes do not
m = Map.new m.set(:h, :a, 0, 42) m.has?(:h, :a) #=> true p m #=> => {'a' => [42]} m.set(:h, :a, 1, 42.0) p m #=> => {'a' => [42, 42.0]}
m.get(:h, :a, 1) #=> 42.0
m.get(:x, :y, :z) #=> nil
m[:x][:y][:z] #=> raises exception!
m = Map.new(:array => [0,1])
defaults = {:array => [nil, nil, 2]}
m.apply(defaults)
p m[:array] #=> [0,1,2]
they also support some different iteration styles
m = Map.new
m.set(
[:a, :b, :c, 0] => 0,
[:a, :b, :c, 1] => 10,
[:a, :b, :c, 2] => 20,
[:a, :b, :c, 3] => 30
)
m.set(:x, :y, 42)
m.set(:x, :z, 42.0)
m.depth_first_each do |key, val|
p key => val
end
#=> [:a, :b, :c, 0] => 0
#=> [:a, :b, :c, 1] => 10
#=> [:a, :b, :c, 2] => 20
#=> [:a, :b, :c, 3] => 30
#=> [:x, :y] => 42
#=> [:x, :z] => 42.0
USAGE see lib/map.rb and test/map_test.rb
HISTORY 4.3.0: - support for dot keys. map.set('a.b.c' => 42) #=> 'a'=>{'b'=>{'c'=>42}}