the ruby container you've always wanted: an ordered string/symbol indifferent hash
Ruby
Latest commit 0a1dc83 Jan 13, 2016 @ahoward simpler to_yaml. v6.6
Permalink
Failed to load latest commit information.
lib simpler to_yaml. v6.6 Jan 12, 2016
pkg simpler to_yaml. v6.6 Jan 12, 2016
test test get set and has? with negative array indexes Jun 17, 2014
.gitignore
LICENSE add license Jul 27, 2011
README Update README Jun 23, 2014
Rakefile version Feb 22, 2014
map.gemspec simpler to_yaml. v6.6 Jan 12, 2016

README

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
#
  p m[:a]  #=> 0
  p m["a"] #=> 0

# even via deep nesting 
#
  p m[:foo]['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 => {:hashes => {:are => :converted}}

# maps can give back clever little struct objects
#
  m = Map(:foo => {:bar => 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.options(: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 = {:read_only => false}
  read_only = options[:read_only] || 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                    #=> {'h' => {'a' => [42]}} 
  m.set(:h, :a, 1, 42.0)
  p m                    #=> {'h' => {'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}}}