Methods
Public Class methods
zipnew(keys,values)

Creates a new hash from two arrays —a keys array and a values array.

  Hash.zipnew(["a","b","c"], [1,2,3])
    #=> { "a"=>1, "b"=>2, "c"=>3 }
# File lib/facets/core/hash/self/zipnew.rb, line 9
  def self.zipnew(keys,values) # or some better name
    h = {}
    keys.size.times{ |i| h[ keys[i] ] = values[i] }
    h
  end
Public Instance methods
[]( *sliceKeys )

Adds slicing to Hash#[]. If more than one key arguments is given to Hash#[], the return value will be an array of the corresponding values.

  h = { :a => 1, :b => 2, :c => 3 }
  h[:a]            #=> 1
  h[:a, :b]        #=> [1,2]
# File lib/facets/core/hash/op_fetch.rb, line 13
  def []( *sliceKeys )
    if sliceKeys.length == 1
      return at( sliceKeys[0] )
    else
      return values_at( *sliceKeys )
    end
  end
[]=( *args )

Add slicing to element assignment operator.

  h = {:a=>1, :b=>2, :c=>3}

  h[:a] = 9              #=> 9
  h                      #=> {:a=>9, :b=>2, :c=>3}

  h[:a, :c] = [10,11]    #=> [10,11]
  h                      #=> {:a=>10, :b=>2, :c=>11}
# File lib/facets/core/hash/op_fetch.rb, line 31
  def []=( *args )
    if args.length <= 2
      return store( *args )
    end
    aVals = args.pop
    aVals = [aVals] unless aVals.kind_of?( Array )
    args.each_index{ |i| store( args[i], aVals[i] ) }
  end
alias!( newkey, oldkey )

Modifies the receiving Hash so that the value previously referred to by oldkey is also referenced by newkey; oldkey is retained in the Hash. If oldkey does not exist as a key in the Hash, no change is effected.

Returns a reference to the Hash.

  foo = { :name=>'Gavin', 'wife'=>:Lisa }
  foo.alias!('name',:name)     => { :name=>'Gavin', 'name'=>'Gavin', 'wife'=>:Lisa }

  foo = { :name=>'Gavin', 'wife'=>:Lisa }
  foo.alias!('spouse','wife')  => { :name=>'Gavin', 'wife'=>:Lisa, 'spouse'=>:Lisa }

  foo = { :name=>'Gavin', 'wife'=>:Lisa }
  foo.alias!('bar','foo')      => { :name=>'Gavin', 'wife'=>:Lisa }

Note that if the oldkey is reassigned, the reference will no longer exist, and the newkey will remain as it was.

# File lib/facets/core/hash/alias.rb, line 23
  def alias!( newkey, oldkey )
    self[newkey] = self[oldkey] if self.has_key?(oldkey)
    self
  end
assert_has_keys(*check_keys)

Returns true is hash has the given keys, otherwise throws an ArgumentError.

  h = { :a => 1, :b => 2 }
  h.assert_has_keys( :a )   #=> true
  h.assert_has_keys( :c )   #=> ArgumentError
# File lib/facets/core/hash/assert_has_keys.rb, line 12
  def assert_has_keys(*check_keys)
    raise(ArgumentError, "does not have key(s)") unless has_keys?(*check_keys)
  end
assert_has_only_keys(*check_keys)

Returns true is hash has only then given keys, otherwise throws an ArgumentError.

  h = { :a => 1, :b => 2 }
  h.assert_has_only_keys( :a, :b )   #=> true
  h.assert_has_only_keys( :a )       #=> ArgumentError
# File lib/facets/core/hash/assert_has_only_keys.rb, line 12
  def assert_has_only_keys(*check_keys)
    raise(ArgumentError, "has unexpected key(s)") unless has_only_keys?(*check_keys)
  end
at_rand()

Alias for rand_value

at_rand!()

Alias for rand_value!

collate( {|| ...}

Returns a new hash built by iterating through each key,value pair and updating the new hash.

# File lib/facets/core/hash/collate.rb, line 12
  def collate  # :yield:
    newhash = {}
    each_pair{ |k,v| newhash.update( yield(k,v) ) }
    newhash
  end
collate!(&yld)

In place version of collate.

# File lib/facets/core/hash/collate.rb, line 19
  def collate!(&yld)
    replace( collate(&yld) )
  end
delete_unless(&block)
# File lib/facets/core/hash/delete_unless.rb, line 3
  def delete_unless (&block)
    delete_if { |key, value| not block.call(key, value) }
  end
each() {|v| ...}

A "smarter" hasheach which iterates through each value if only one block parameter is given.

  {:a=>"a", 2=>"b", "x"=>"c"}.each{ |v| puts v }

produces

  a
  b
  c

WARNING! Use with caution. Methods from other libraries may depend on the old behavior, expecting a two element array to be passed into a single block argument.

# File lib/facets/core/hash/each.rb, line 19
  def each(&yld)
    case yld.arity
    when 0
    when 1
      each_value{|v| yield(v)}
    else
      each_pair{|k,v| yld.call(k,v)}
    end
    self
  end
each_with_index( &yld )

Alias for each_with_key

each_with_key( &yld )
This method is also aliased as each_with_index
# File lib/facets/core/hash/each_with_key.rb, line 4
  def each_with_key( &yld )
    each_pair{ |k,v| yld.call(v,k) }
  end
graph!( &blk )

As with Enumerable#graph but acts in place.

# File lib/facets/core/hash/graph.rb, line 5
  def graph!( &blk )
    self.replace( graph( &blk ) )
  end
has_keys?(*check_keys)

Returns true or false whether the hash contains the given keys.

  h = { :a => 1, :b => 2 }
  h.has_keys?( :a )   #=> true
  h.has_keys?( :c )   #=> false
# File lib/facets/core/hash/has_keys.rb, line 10
  def has_keys?(*check_keys)
    unknown_keys = check_keys - self.keys
    return unknown_keys.empty?
  end
has_only_keys?(*check_keys)

Returns true if the hash contains only the given keys, otherwise false.

  h = { :a => 1, :b => 2 }
  h.has_only_keys?( :a, :b )   #=> true
  h.has_only_keys?( :a )       #=> false
# File lib/facets/core/hash/has_only_keys.rb, line 10
  def has_only_keys?(*check_keys)
    unknown_keys = self.keys - check_keys
    return unknown_keys.empty?
  end
inverse()

Create a "true" inverse hash by storing mutliple values in Arrays.

  h = {"a"=>3, "b"=>3, "c"=>3, "d"=>2, "e"=>9, "f"=>3, "g"=>9}

  h.invert                #=> {2=>"d", 3=>"f", 9=>"g"}
  h.inverse               #=> {2=>"d", 3=>["f", "c", "b", "a"], 9=>["g", "e"]}
  h.inverse.inverse       #=> {"a"=>3, "b"=>3, "c"=>3, "d"=>2, "e"=>9, "f"=>3, "g"=>9}
  h.inverse.inverse == h  #=> true
# File lib/facets/core/hash/inverse.rb, line 16
  def inverse
    i = Hash.new
    self.each_pair{ |k,v|
      if (Array === v)
        v.each{ |x| i[x] = ( i.has_key?(x) ? [k,i[x]].flatten : k ) }
      else
        i[v] = ( i.has_key?(v) ? [k,i[v]].flatten : k )
      end
    }
    return i
  end
join( pair_divider='', elem_divider='' )
# File lib/facets/core/hash/join.rb, line 4
  def join( pair_divider='', elem_divider='' )
    s = []
    each_pair { |k,v| s << "#{k}#{pair_divider}#{v}" }
    s.join(elem_divider)
  end
keys_to_s( from_class=nil )

Converts all keys in the Hash to be String values, returning a new Hash. With a from_class parameter, limits conversion to only a certain class of keys. It defaults to nil which convert any key class.

  foo = { :name=>'Gavin', :wife=>:Lisa }
  foo.keys_to_s    #=>  { "name"=>"Gavin", "wife"=>:Lisa }
  foo.inspect      #=>  { :name =>"Gavin", :wife=>:Lisa }
This method is also aliased as stringify_keys
# File lib/facets/core/hash/keys_to_s.rb, line 15
  def keys_to_s( from_class=nil )
    raise ArgumentError, "Parameter must be a class" unless from_class.kind_of?(Class) if from_class
    self.dup.keys_to_s!( from_class )
  end
keys_to_s!( from_class=nil )

Synonym for Hash#keys_to_string, but modifies the receiver in place (and returns it). With a from_class parameter, limits conversion to only a certain class of keys. It defaults to nil which convert any key class.

  foo = { :name=>'Gavin', :wife=>:Lisa }
  foo.keys_to_s!    #=>  { "name"=>"Gavin", "wife"=>:Lisa }
  foo.inspect       #=>  { "name"=>"Gavin", "wife"=>:Lisa }
This method is also aliased as stringify_keys!
# File lib/facets/core/hash/keys_to_s.rb, line 34
  def keys_to_s!( from_class=nil )
    raise ArgumentError, "Parameter must be a class" unless from_class.kind_of?(Class) if from_class
    if from_class
      self.each_key{ |k|
        self[k.to_s]=self.delete(k) if k.respond_to?(:to_s) and k.class == from_class
      }
    else
      self.each_key{ |k|
        self[k.to_s]=self.delete(k) if k.respond_to?(:to_s)
      }
    end
    self
  end
keys_to_sym( from_class=String )

Converts all keys in the Hash to be Symbol values, returning a new Hash. With a from_class parameter, limits conversion to only a certain class of keys. It defaults to String —use nil to convert any key class.

  foo = { :name=>'Gavin', 'wife'=>:Lisa }
  foo.keys_to_sym    #=>  { :name=>"Gavin", :wife=>:Lisa }
  foo.inspect        #=>  { "name" =>"Gavin", "wife"=>:Lisa }
This method is also aliased as symbolize_keys
# File lib/facets/core/hash/keys_to_sym.rb, line 15
  def keys_to_sym( from_class=String )
    raise ArgumentError, "Parameter must be a class" unless from_class.kind_of?(Class) if from_class
    self.dup.keys_to_sym!( from_class )
  end
keys_to_sym!( from_class=String )

Synonym for Hash#keys_to_symbol, but modifies the receiver in place (and returns it). With a from_class parameter, limits conversion to only a certain class of keys. It defaults to String —use nil to convert any key class.

  foo = { 'name'=>'Gavin', 'wife'=>:Lisa }
  foo.keys_to_sym!    #=>  { :name=>"Gavin", :wife=>:Lisa }
  foo.inspect         #=>  { :name=>"Gavin", :wife=>:Lisa }
This method is also aliased as symbolize_keys!
# File lib/facets/core/hash/keys_to_sym.rb, line 40
  def keys_to_sym!( from_class=String )
    raise ArgumentError, "Parameter must be a class" unless from_class.kind_of?(Class) if from_class
    if from_class
      self.each_key{ |k|
        self[k.to_sym]=self.delete(k) if k.respond_to?(:to_sym) and k.class == from_class
      }
    else
      self.each_key{ |k|
        self[k.to_sym]=self.delete(k) if k.respond_to?(:to_sym)
      }
    end
    self
  end
pick()

Alias for rand_value!

pick_key()

Alias for rand_key!

pick_pair()

Alias for rand_pair!

rand_key()

Returns a random key.

  {:one => 1, :two => 2, :three => 3}.pick_key  #=> :three
# File lib/facets/core/hash/rand_key.rb, line 7
  def rand_key
    keys.at( rand(keys.size) )
  end
rand_key!()

Delete a random key-value pair, returning the key.

  a = {:one => 1, :two => 2, :three => 3}
  a.pick_key!  #=> :two
  a            #=> {:one => 1, :three => 3}
This method is also aliased as pick_key
# File lib/facets/core/hash/rand_key.rb, line 17
  def rand_key!
    k,v = rand_pair
    delete( k )
    return k
  end
rand_pair()

Returns a random key-value pair.

  {:one => 1, :two => 2, :three => 3}.pick  #=> [:one, 1]
# File lib/facets/core/hash/rand_pair.rb, line 9
  def rand_pair
    k = rand_key
    return k, fetch(k)
  end
rand_pair!()

Deletes a random key-value pair and returns that pair.

  a = {:one => 1, :two => 2, :three => 3}
  a.rand_pair!  #=> [:two, 2]
  a             #=> {:one => 1, :three => 3}
This method is also aliased as pick_pair
# File lib/facets/core/hash/rand_pair.rb, line 20
  def rand_pair!
    k,v = rand_pair
    delete( k )
    return k,v
  end
rand_value()

Returns a random hash value.

  {:one => 1, :two => 2, :three => 3}.rand_value  #=> 2
  {:one => 1, :two => 2, :three => 3}.rand_value  #=> 1
This method is also aliased as at_rand
# File lib/facets/core/hash/rand_value.rb, line 16
  def rand_value
    fetch( rand_key )
  end
rand_value!()

Deletes a random key-value pair and returns the value.

  a = {:one => 1, :two => 2, :three => 3}
  a.at_rand!  #=> 2
  a           #=> {:one => 1, :three => 3}
This method is also aliased as pick at_rand!
# File lib/facets/core/hash/rand_value.rb, line 26
  def rand_value!
    k,v = rand_pair
    delete( k )
    return v
  end
replace_each( {|| ...}

Same as update_each, but deletes the key element first.

# File lib/facets/core/hash/replace_each.rb, line 4
  def replace_each  # :yield:
    dup.each_pair{ |k,v| delete( k ); update( yield(k,v) ); }
    self
  end
shuffle()

Returns a copy of the hash with values arranged in new random order.

  h = {:a=>1, :b=>2, :c=>3}
  h.shuffle_hash  #=> {:b=>2, :c=>1, :a>3}
# File lib/facets/core/hash/shuffle.rb, line 11
  def shuffle
    Hash.zipnew( keys.sort_by{Kernel.rand}, values.sort_by{Kernel.rand} )
  end
shuffle!()

Destructive shuffle_hash. Arrange the values in a new random order.

  h = {:a => 1, :b => 2, :c => 3}
  h.shuffle_hash!
  h  #=> {:b=>2, :c=>1, :a=>3}
# File lib/facets/core/hash/shuffle.rb, line 22
  def shuffle!
    self.replace( shuffle )
  end
stringify_keys( from_class=nil )

Alias for keys_to_s

stringify_keys!( from_class=nil )

Alias for keys_to_s!

swap!( key1, key2 )

Swap the values of a pair of keys in place.

  {:a=>1,:b=>2}.swap!  #=> {:a=>2,:b=>1}
# File lib/facets/core/hash/swap.rb, line 7
  def swap!( key1, key2 )
    tmp = self[key1]
    self[key1] = self[key2]
    self[key2] = tmp
    self
  end
swapkey!( newkey, oldkey )

Modifies the receiving Hash so that the value previously referred to by oldkey is referenced by newkey; oldkey is removed from the Hash. If oldkey does not exist as a key in the Hash, no change is effected.

Returns a reference to the Hash.

  foo = { :a=>1, :b=>2 }
  foo.swapkey!('a',:a)       #=> { 'a'=>1, :b=>2 }
  foo.swapkey!('b',:b)       #=> { 'a'=>1, 'b'=>2 }
  foo.swapkey!('foo','bar')  #=> { 'a'=>1, 'b'=>2 }
# File lib/facets/core/hash/swapkey.rb, line 16
  def swapkey!( newkey, oldkey )
    self[newkey] = self.delete(oldkey) if self.has_key?(oldkey)
    self
  end
symbolize_keys( from_class=String )

Alias for keys_to_sym

symbolize_keys!( from_class=String )

Alias for keys_to_sym!

to_h()

Return a rehashing of self.

  {"a"=>1,"b"=>2}.to_h  #=> {"b"=>2,"a"=>1}
# File lib/facets/core/hash/to_h.rb, line 10
  def to_h; rehash; end
to_ostruct()

Turns a hash into a generic object using an OpenStruct.

  o = { 'a' => 1 }.to_ostruct
  o.a  #=> 1
# File lib/facets/core/hash/to_ostruct.rb, line 10
  def to_ostruct
    OpenStruct.new( self )
  end
to_ostruct_recurse( exclude={} )

Like to_ostruct but recusively objectifies all hash elements as well.

    o = { 'a' => { 'b' => 1 } }.to_ostruct_recurse
    o.a.b  #=> 1

The exclude parameter is used internally to prevent infinite recursion and is not intended to be utilized by the end-user. But for more advance use, if there is a particular subhash you would like to prevent from being converted to an OpoenStruct then include it in the exclude hash referencing itself. Eg.

    h = { 'a' => { 'b' => 1 } }
    o = h.to_ostruct_recurse( { h['a'] => h['a'] } )
    o.a['b']  #=> 1
# File lib/facets/core/hash/to_ostruct_recurse.rb, line 26
  def to_ostruct_recurse( exclude={} )
    return exclude[self] if exclude.key?( self )
    o = exclude[self] = OpenStruct.new
    h = self.dup
    each_pair do |k,v|
      h[k] = v.to_ostruct_recurse( exclude ) if v.respond_to?( :to_ostruct_recurse )
    end
    o.__update__( h )
  end
to_proc()

Constructs a Proc object from a hash such that the parameter of the Proc is assigned the hash keys as attributes.

  h = { :a => 1 }
  p = h.to_proc
  o = OpenStruct.new
  p.call(o)
  o.a  #=> 1
# File lib/facets/core/hash/to_proc.rb, line 15
  def to_proc
    lambda do |o|
      self.each do |k,v|
        ke = "#{k}="
        o.__send__(ke, v)
      end
    end
  end
to_proc_with_reponse()
# File lib/facets/core/hash/to_proc.rb, line 24
  def to_proc_with_reponse
    lambda do |o|
      self.each do |k,v|
        ke = "#{k}="
        o.__send__(ke, v) if respond_to?(ke)
      end
    end
  end
traverse(&b)

Returns a new hash created by traversing the hash and its subhashes, executing the given block on the key and value. The block should return a 2-element array of the form +[key, value]+.

  h = { "A"=>"A", "B"=>"B" }
  g = h.traverse { |k,v| [k.downcase, v] }
  g  #=> { "a"=>"A", "b"=>"B" }
# File lib/facets/core/hash/traverse.rb, line 16
  def traverse(&b)
    inject({}) do |h,(k,v)|
      v = ( Hash === v ? v.traverse(&b) : v )
      nk, nv = b[k,v]
      h[nk] = nv #( Hash === v ? v.traverse(base,&b) : nv )
      h
    end
  end
traverse!(&b)

In place version of traverse, which traverses the hash and its subhashes, executing the given block on the key and value.

  h = { "A"=>"A", "B"=>"B" }
  h.traverse! { |k,v| [k.downcase, v] }
  h  #=> { "a"=>"A", "b"=>"B" }
# File lib/facets/core/hash/traverse.rb, line 32
  def traverse!(&b)
    self.replace( self.traverse(&b) )
  end
update_each( {|| ...}

Iterates through each pair and updates a the hash in place. This is formally equivalent to collate! But does not use collate to accomplish the task. Hence update_each is probably a bit faster.

  # TODO
# File lib/facets/core/hash/update_each.rb, line 14
  def update_each  # :yield:
    dup.each_pair{ |k,v| update( yield(k,v) ); }
    self
  end
update_keys() {|k| ...}
# File lib/facets/core/hash/update_keys.rb, line 4
  def update_keys
    each{ |k,v| delete(k) ; store( yield(k), v ) }
  end
update_values() {|v| ...}
# File lib/facets/core/hash/update_values.rb, line 4
  def update_values
    each{ |k,v| store( k, yield(v) ) }
  end
variablize_keys( of_class=nil )

Converts all keys in the Hash to be String values, returning a new Hash. With a from_class parameter, limits conversion to only a certain class of keys. It defaults to nil which convert any key class.

  foo = { :name=>'Gavin', :wife=>:Lisa }
  foo.variablize_keys    #=>  { "@name"=>"Gavin", "@wife"=>:Lisa }
  foo.inspect            #=>  { :name =>"Gavin", :wife=>:Lisa }
# File lib/facets/core/hash/variablize_keys.rb, line 11
  def variablize_keys( of_class=nil )
    self.dup.variablize_keys!( of_class )
  end
variablize_keys!( of_class=nil )

Synonym for Hash#keys_to_string, but modifies the receiver in place (and returns it). With a from_class parameter, limits conversion to only a certain class of keys. It defaults to nil which convert any key class.

  foo = { :name=>'Gavin', :wife=>:Lisa }
  foo.variablize_keys!   #=>  { "@name"=>"Gavin", "@wife"=>:Lisa }
  foo.inspect            #=>  { "@name"=>"Gavin", "@wife"=>:Lisa }
# File lib/facets/core/hash/variablize_keys.rb, line 23
  def variablize_keys!( of_class=nil )
    raise ArgumentError, "Parameter must be a class" unless of_class.kind_of?(Class) if of_class
    if of_class
      self.each_key do |k|
        if k.respond_to?(:to_s) and k.class == of_class
          k = k.to_s
          nk = k[0,1] != '@' ? k : "@#{k}"
          self[nk]=self.delete(k)
        end
      end
    else
      self.each_key do |k|
        if k.respond_to?(:to_s)
          k = k.to_s
          nk = k[0,1] != '@' ? k : "@#{k}"
          self[nk]=self.delete(k)
        end
      end
    end
    self
  end
weave(h)

Weaves two hashes producing a new hash. The two hashes need to be compatible according to the following rules for each node:

  <tt>
  hash, hash => hash (recursive +)
  hash, array => error
  hash, value => error
  array, hash => error
  array, array => array + array
  array, value => array << value
  value, hash => error
  value, array => array.unshift(valueB)
  valueA, valueB => valueB
  </tt>

Example:

  # to do
# File lib/facets/core/hash/weave.rb, line 23
  def weave(h)
    raise ArgumentError, "Hash expected" unless h.kind_of?(Hash)
    s = self.clone
    h.each { |k,node|
      node_is_hash = node.kind_of?(Hash)
      node_is_array = node.kind_of?(Array)
      if s.has_key?(k)
        self_node_is_hash = s[k].kind_of?(Hash)
        self_node_is_array = s[k].kind_of?(Array)
        if self_node_is_hash
          if node_is_hash
            s[k] = s[k].weave(node)
          elsif node_is_array
            raise ArgumentError, 'Incompatible hash addition' #self[k] = node
          else
            raise ArgumentError, 'Incompatible hash addition' #self[k] = node
          end
        elsif self_node_is_array
          if node_is_hash
            raise ArgumentError, 'Incompatible hash addition' #self[k] = node
          elsif node_is_array
            s[k] += node
          else
            s[k] << node
          end
        else
          if node_is_hash
            raise ArgumentError, 'Incompatible hash addition' #self[k] = node
          elsif node_is_array
            s[k].unshift( node )
          else
            s[k] = node
          end
        end
      else
        s[k] = node
      end
    }
    s
  end