# class Hash

### Public Class Methods

autonew(*args) click to toggle source

Hash which auto initializes it's children.

    h = Hash.autonew
    h['s1']['p1'] = 4
    h['s1']['p2'] = 5
    h['s1']['p3'] = 2
    h['s1']['p4'] = 3

    h #=> {"s1"=>{"p1"=>4, "p4"=>3, "p3"=>2, "p2"=>5}}

    h['s1'].keys.sort
    #=> ["p1", "p2", "p3", "p4"]

CREDIT: Trans, Jan Molic

    # File lib/facets/hash/autonew.rb, line 18
    def self.autonew(*args)
      leet = lambda{ |hsh, key| hsh[key] = new( &leet ) }
      new(*args,&leet)
    end

new_with() { || ... } click to toggle source

Instantiate a new hash with a default value determined by the block.

::new_with{ [] }

CREDIT: Pit Capitan

    # File lib/facets/hash/new_with.rb, line 10
    def self.new_with #:yield:
      new { |h, k| h[k] = yield }
    end

zip(keys,values) click to toggle source

Creates a new hash from two separate arrays, a `keys` array and a `values` array.

    Hash.zip(["a","b","c"], [1,2,3])
    # => { "a"=>1, "b"=>2, "c"=>3 }

CREDIT: Trans, Ara T. Howard

    # File lib/facets/hash/zip.rb, line 11
    def self.zip(keys,values) # or some better name
      h = {}
      keys.size.times{ |i| h[ keys[i] ] = values[i] }
      h
    end

### Public Instance Methods

&(other) click to toggle source

Hash intersection. Two hashes intersect when their pairs are equal.

    ({:a=>1,:b=>2} & {:a=>1,:c=>3})  #=> {:a=>1}

A hash can also be intersected with an array to intersect keys only.

    ({:a=>1,:b=>2} & [:a,:c])  #=> {:a=>1}

The later form is similar to pairs_at. The differ only in that pairs_at will return a nil value for a key not in the hash, but #& will not.

CREDIT: Trans

    # File lib/facets/hash/op_and.rb, line 19
    def &(other)
      case other
      when Array
        k = (keys & other)
        Hash[*(k.zip(values_at(*k)).flatten)]
      else
        x = (to_a & other.to_a).inject([]) do |a, kv|
          a.concat kv; a
        end
        Hash[*x]
      end
    end

*(other) click to toggle source

Like merge operator '+' but merges in reverse order.

    h1 = {:a=>1}
    h2 = {:a=>2, :b=>3}

    (h1 + h2) #=> { :a=>2, :b=>3 }
    (h1 * h2)  #=> { :a=>1, :b=>3 }

CREDIT: Trans

    # File lib/facets/hash/op_mul.rb, line 13
    def *(other)
      other.merge(self)
    end

+(other) click to toggle source

Operator for merge.

CREDIT: Trans

    # File lib/facets/hash/op_add.rb, line 7
    def +(other)
      merge(other)
    end

-(other) click to toggle source

Operator for remove hash paris. If another hash is given the pairs are only removed if both key and value are equal. If an array is given then matching keys are removed.

CREDIT: Trans CREDIT: Xavier Shay (bug fix)

    # File lib/facets/hash/op_sub.rb, line 10
    def -(other)
      h = self.dup
      if other.respond_to?(:to_ary)
        other.to_ary.each do |k|
          h.delete(k)
        end
      else
        other.each do |k,v|
          if h.key?(k)
            h.delete(k) if v == h[k]
          end
        end
      end
      h
    end

<<(other) click to toggle source

Can be used like update, or passed as two-element [key,value] array.

CREDIT: Trans

    # File lib/facets/hash/op_push.rb, line 8
    def <<(other)
      if other.respond_to?(:to_ary)
        self.store(*other)
      else
        update(other)
      end
      self
    end

alias!(newkey, oldkey) click to toggle source

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.

CREDIT: Gavin Sinclair

TODO: Rename to aliaskey or something else.

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

argumentize(args_field=nil) click to toggle source

Turn a hash into a method arguments.

    h = { :list => [1,2], :base => "HI" }

Without an argument field.

    h.argumentize #=> [ { :list => [1,2], :base => "HI" } ]

With an argument field.

    h.argumentize(:list)   #=> [ 1, 2, { :base => "HI" } ]
    h.argumentize(:base)   #=> [ "HI", { :list => [1,2] } ]

    # File lib/facets/hash/argumentize.rb, line 16
    def argumentize(args_field=nil)
      config = dup
      if args_field
        args = [config.delete(args_field)].flatten.compact
      else
        args = []
      end
      args << config
      return args
    end

collate(other) click to toggle source

Merge the values of this hash with those from another, setting all values to be arrays representing the values from both hashes.

    { :a=>1, :b=>2 }.collate(:a=>3, :b=>4, :c=>5)
    #=> { :a=>[1,3], :b=>[2,4], :c=>[5] }

@author Trans (rewrite) @author Tilo Sloboda (bug fixes) @author Gavin Kistner (original)

    # File lib/facets/hash/collate.rb, line 13
    def collate(other)
      h = Hash.new
      (keys + other.keys).each do |key|
        h[key] = []
      end
      each do |key, value|
        h[key] << value
      end
      other.each do |key, value|
        h[key] << value
      end
      h.each{ |k,v| v.flatten! }
      h
    end

collate!(other_hash) click to toggle source

The same as collate, but modifies the receiver in place.

    # File lib/facets/hash/collate.rb, line 29
    def collate!(other_hash)
      result = collate(other_hash)
      replace(result)
    end

count(value) click to toggle source

Like Enumerable#count, but counts hash values.

    {:A=>1, :B=>1}.count(1) #=> 2

    # File lib/facets/hash/count.rb, line 7
    def count(value)
      values.count(value)
    end

data() click to toggle source

Access to a hash as if it were an OpenStruct.

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

    h.data.a  #=> 1
    h.data.b  #=> 2
    h.data.c  #=> nil

    h.data.c = 3
    h.data.c  #=> 3

    h.data.a?  #=> true
    h.data.d?  #=> false

TODO: Change name of #data to something better?

TODO: Is this really a method worth having?

    # File lib/facets/hash/data.rb, line 22
    def data
      this = self
      Functor.new do |op, *a|
        case op.to_s
        when /\=$/
          op = op.to_s.chomp('=')
          this[op] = a.first
        when /\?$/
          op = op.to_s.chomp('?')
          this.key?(op.to_s) || this.key?(op.to_sym)
        when /\!$/
          op = op.to_s.chomp('!')
          this[op] # ???
        else
          this[op.to_s] || this[op.to_sym]
        end
      end
    end

dearray_singular_values() click to toggle source

Any array values with one or no elements will be set to the element or nil.

    h = { :a=>[1], :b=>[1,2], :c=>3, :d=>[] }
    h.dearray_singular_values  #=> { :a=>1, :b=>[1,2], :c=>3, :d=>nil }

CREDIT: Trans

    # File lib/facets/hash/dearray_values.rb, line 32
    def dearray_singular_values
      h = {}
      each do |k,v|
        case v
        when Array
          h[k] = (v.size < 2) ? v[0] : v
        else
          h[k] = v
        end
      end
      h
    end

dearray_values(index=0) click to toggle source

Any array values with be replaced with the first element of the array. Arrays with no elements will be set to nil.

    h = { :a=>[1], :b=>[1,2], :c=>3, :d=>[] }
    h.dearray_values  #=> { :a=>1, :b=>1, :c=>3, :d=>nil }

CREDIT: Trans

    # File lib/facets/hash/dearray_values.rb, line 11
    def dearray_values(index=0)
      h = {}
      each do |k,v|
        case v
        when Array
          h[k] = v[index] || v[-1]
        else
          h[k] = v
        end
      end
      h
    end

deep_merge(other) click to toggle source

Same as Hash#merge but recursively merges sub-hashes.

    # File lib/facets/hash/deep_merge.rb, line 5
    def deep_merge(other)
      hash = self.dup
      other.each do |key, value|
        myval = self[key]
        if value.is_a?(Hash) && myval.is_a?(Hash)
          hash[key] = myval.deep_merge(value)
        else
          hash[key] = value
        end
      end
      hash
    end

deep_merge!(other) click to toggle source

Same as Hash#merge! but recursively merges sub-hashes.

    # File lib/facets/hash/deep_merge.rb, line 20
    def deep_merge!(other)
      other.each do |key, value|
        myval = self[key]
        if value.is_a?(Hash) && myval.is_a?(Hash)
          myval.deep_merge!(value)
        else
          self[key] = value
        end
      end
      self
    end

delete_unless() { || ... } click to toggle source

Inverse of delete_if.

    h = { :a => 1, :b => 2, :c => 3 }
    r = h.delete_unless{|k,v| v == 1}
    r  #=> { :a => 1 }
    h  #=> { :a => 1 }

CREDIT: Daniel Schierbeck

    # File lib/facets/hash/delete_unless.rb, line 12
    def delete_unless #:yield:
      delete_if{ |key, value| ! yield(key, value) }
    end

delete_values(*values) click to toggle source

Minor modification to Ruby's Hash#delete method allowing it to take multiple keys.

    hsh = { :a => 1, :b => 2 }
    hsh.delete_values(1)
    hsh  #=> { :b => 2 }

Returns a list of keys of the deleted entries.

CREDIT: Daniel Schierbeck

    # File lib/facets/hash/delete_values.rb, line 14
    def delete_values(*values)
      deleted_keys = []
      keys.each do |key|
        if values.include?(fetch(key))
          deleted_keys << key
          delete(key)
        end
      end
      deleted_keys
    end

delete_values_at(*keys, &yld) click to toggle source

Minor modification to Ruby's Hash#delete method allowing it to take multiple keys.

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

    a, b, c = hsh.delete_values_at(:a, :b, :c)

    [a, b, c]  #=> [1, 2, 3]
    hsh        #=> {}

CREDIT: Daniel Schierbeck

    # File lib/facets/hash/delete_values.rb, line 37
    def delete_values_at(*keys, &yld)
      keys.map{|key| delete(key, &yld) }
    end

diff(hash) click to toggle source

Difference comparison of two hashes.

    h1 = {:a=>1,:b=>2}
    h2 = {:a=>1,:b=>3}

    h1.diff(h2)  #=> {:b=>2}
    h2.diff(h1)  #=> {:b=>3}

    # File lib/facets/hash/diff.rb, line 11
    def diff(hash)
      h1 = self.dup.delete_if{ |k,v| hash[k] == v }
      h2 = hash.dup.delete_if{ |k,v| has_key?(k) }
      h1.merge(h2)
    end

each_with_key( &yld ) click to toggle source

Each with key is like each_pair but reverses the order the parameters to [value,key] instead of [key,value].

CREDIT: Trans

    # File lib/facets/hash/keys.rb, line 40
    def each_with_key( &yld )
      each_pair{ |k,v| yld.call(v,k) }
    end

except(*less_keys) click to toggle source

Returns a new hash less the given keys.

    # File lib/facets/hash/except.rb, line 4
    def except(*less_keys)
      hash = dup
      less_keys.each{ |k| hash.delete(k) }
      hash
    end

except!(*rejected) click to toggle source

Replaces hash with new hash less the given keys. This returns the hash of keys removed.

    h = {:a=>1, :b=>2, :c=>3}
    h.except!(:a)  #=> {:a=>1}
    h              #=> {:b=>2,:c=>3}

Returns a Hash of the removed pairs.

    # File lib/facets/hash/except.rb, line 18
    def except!(*rejected)
      removed = {}
      rejected.each{ |k| removed[k] = delete(k) }
      removed
    end

extractable_options?() click to toggle source

By default, only instances of Hash itself are extractable. Subclasses of Hash may implement this method and return true to declare themselves as extractable. If a Hash is extractable, Array#extract_options! pops it from the Array when it is the last element of the Array.

    # File lib/facets/array/extract_options.rb, line 7
    def extractable_options?
      instance_of?(Hash)
    end

graph!(&yld) click to toggle source

In place version of graph.

NOTE: #graph! is only useful for Hash. It is not generally applicable to Enumerable.

    # File lib/facets/hash/graph.rb, line 10
    def graph!(&yld)
      replace(graph(&yld))
    end

Also aliased as: mash!
has_keys?(*check_keys) click to toggle source

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

CREDIT: Trans

    # File lib/facets/hash/keys.rb, line 12
    def has_keys?(*check_keys)
      unknown_keys = check_keys - self.keys
      return unknown_keys.empty?
    end

Also aliased as: keys?
has_only_keys?(*check_keys) click to toggle source

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

CREDIT: Trans

    # File lib/facets/hash/keys.rb, line 28
    def has_only_keys?(*check_keys)
      unknown_keys = self.keys - check_keys
      return unknown_keys.empty?
    end

Also aliased as: only_keys?
insert(name, value) click to toggle source

As with store but only if the key isn't already in the hash.

TODO: Would store? be a better name?

CREDIT: Trans

    # File lib/facets/hash/insert.rb, line 10
    def insert(name, value)
      if key?(name)
        false
      else
        store(name,value)
        true
      end
    end

inverse() click to toggle source

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}

Of course the inverse of the inverse should be the same.

    (h.inverse.inverse == h)  #=> true

CREDIT: Tilo Sloboda

    # File lib/facets/hash/inverse.rb, line 17
    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=nil) click to toggle source

Like Array#join but specialized to Hash.

NOTE: Without Ruby 1.9 this would be difficult to rely on becuase hashes did not have a strict order.

CREDIT: Mauricio Fernandez

    # File lib/facets/hash/join.rb, line 10
    def join(pair_divider='', elem_divider=nil)
      elem_divider ||= pair_divider
      s = []
      each{ |k,v| s << "#{k}#{pair_divider}#{v}" }
      s.join(elem_divider)
    end

keys?(*check_keys)
Alias for: has_keys?
mash!(&yld)

Alias for graph! as an alliteration for “map hash”.

Alias for: graph!
object_state(data=nil) click to toggle source

    # File lib/facets/object/object_state.rb, line 61
    def object_state(data=nil)
      data ? replace(data) : dup
    end

only_keys?(*check_keys)
Alias for: has_only_keys?
recurse(*types) { |h| ... } click to toggle source

Apply a block to hash, and recursively apply that block to each sub-hash or `types`.

    h = {:a=>1, :b=>{:b1=>1, :b2=>2}}
    g = h.recurse{|h| h.inject({}){|h,(k,v)| h[k.to_s] = v; h} }
    g  #=> {"a"=>1, "b"=>{"b1"=>1, "b2"=>2}}

    # File lib/facets/hash/recurse.rb, line 10
    def recurse(*types, &block)
      types = [self.class] if types.empty?
      h = inject({}) do |hash, (key, value)|
        case value
        when *types
          hash[key] = value.recurse(*types, &block)
        else
          hash[key] = value
        end
        hash
      end
      yield h
    end

recurse!(&block) click to toggle source

In place form of recurse.

    # File lib/facets/hash/recurse.rb, line 25
    def recurse!(&block)
      replace(recurse(&block))
    end

recursively(*types, &block) click to toggle source

Apply a block to a hash, and recursively apply that block to each sub-hash:

    h = {:a=>1, :b=>{:x=>1, :y=>2}}
    h.recursively.map{ |k,v| [k.to_s, v] }
    #=> [["a", 1], ["b", [["y", 2], ["x", 1]]]]

The recursive iteration can be treated separately from the non-recursive iteration by passing a block to the recursive method:

    h = {:a=>1, :b=>{:x=>1, :y=>2}}
    h.recursively{ |k,v| [k.to_s, v] }.map{ |k,v| [k.to_s, v.to_s] }
    #=> [["a", "1"], ["b", [["y", "2"], ["x", "1"]]]]

    # File lib/facets/hash/recursively.rb, line 20
    def recursively(*types, &block)
      Recursor.new(self, *types, &block)
    end

rekey(key_map=nil, &block) click to toggle source

Rekey a hash:

    rekey()
    rekey(from_key => to_key, ...)
    rekey{|from_key| to_key}

If a key map is given, then the first key is changed to the second key.

    foo = { :a=>1, :b=>2 }
    foo.rekey(:a=>'a')       #=> { 'a'=>1, :b=>2 }
    foo.rekey(:b=>:x)        #=> { :a =>1, :x=>2 }
    foo.rekey('foo'=>'bar')  #=> { :a =>1, :b=>2 }

If a block is given, converts all keys in the Hash accroding to the given block procedure. If the block returns `NA` for a given key, then that key will be left intact.

    foo = { :name=>'Gavin', :wife=>:Lisa }
    foo.rekey{ |k| k.to_s }  #=>  { "name"=>"Gavin", "wife"=>:Lisa }
    foo                      #=>  { :name =>"Gavin", :wife=>:Lisa }

If no key map or block is given, then all keys are converted to Symbols.

Note that if both a `key_map` and a block are given, the `key_map` is applied first then the block.

CREDIT: Trans, Gavin Kistner

    # File lib/facets/hash/rekey.rb, line 37
    def rekey(key_map=nil, &block)
      if !(key_map or block)
        block = lambda{|k| k.to_sym}
      end

      key_map ||= {}

      hash = dup.replace({})  # to keep default_proc

      (keys - key_map.keys).each do |key|
        hash[key] = self[key]
      end

      key_map.each do |from, to|
        hash[to] = self[from] if key?(from)
      end

      if block
        hash2 = dup.replace({})
        case block.arity
        when 2  # TODO: is this condition needed?
          hash.each do |k, v|
            nk = block.call(k,v)
            nk = (NA == nk ? k : nk)
            hash2[nk] = v
          end
        else
          hash.each do |k, v|
            nk = block.call(k)
            nk = (NA == nk ? k : nk)
            hash2[nk] = v
          end
        end
      else
        hash2 = hash
      end

      hash2
    end

rekey!(key_map=nil, &block) click to toggle source

Synonym for #rekey, but modifies the receiver in place (and returns it).

    foo = { :name=>'Gavin', :wife=>:Lisa }
    foo.rekey!{ |k| k.to_s }  #=>  { "name"=>"Gavin", "wife"=>:Lisa }
    foo                       #=>  { "name"=>"Gavin", "wife"=>:Lisa }

CREDIT: Trans, Gavin Kistner

    # File lib/facets/hash/rekey.rb, line 85
    def rekey!(key_map=nil, &block)
      replace(rekey(key_map, &block))
    end

replace_each() { || ... } click to toggle source

Same as update_each, but deletes the key element first.

CREDIT: Trans

    # File lib/facets/hash/replace_each.rb, line 7
    def replace_each  # :yield:
      dup.each do |k,v|
        delete(k)
        update(yield(k,v))
      end
      self
    end

reverse_merge(other) click to toggle source

Allows for reverse merging where its the keys in the calling hash that wins over those in the `other_hash`. This is particularly useful for initializing an incoming option hash with default values:

    def setup(options = {})
      options.reverse_merge! :size => 25, :velocity => 10
    end

The default :size and :velocity is only set if the `options` passed in doesn't already have those keys set.

    # File lib/facets/hash/reverse_merge.rb, line 15
    def reverse_merge(other)
      other.merge(self)
    end

reverse_merge!(other) click to toggle source

Inplace form of reverse_merge.

    # File lib/facets/hash/reverse_merge.rb, line 21
    def reverse_merge!(other)
      replace(reverse_merge(other))
    end

Also aliased as: reverse_update
reverse_update(other)

Obvious alias for #reverse_merge!

Alias for: reverse_merge!
select!() { |k,v| ... } click to toggle source

In-place version of Hash#select. The opposite of the built-in Hash#reject!.

CREDIT: Gavin Sinclair, Noah Gibbs

    # File lib/facets/hash/select.rb, line 10
    def select!
      reject! { |k,v| not yield(k,v) }
    end

slice(*keep_keys) click to toggle source

Returns a new hash with only the given keys.

    h = {:a=>1, :b=>2}
    h.slice(:a)  #=> {:a=>1}

    # File lib/facets/hash/slice.rb, line 8
    def slice(*keep_keys)
      hash = {}
      keep_keys.each do |key|
        hash[key] = fetch(key)
      end
      hash
    end

slice!(*keep_keys) click to toggle source

Replaces hash with a new hash having only the given keys. This return the hash of keys removed.

    h = {:a=>1, :b=>2}
    h.slice!(:a)  #=> {:b=>2}
    h             #=> {:a=>1}

Returns a Hash of the removed pairs.

    # File lib/facets/hash/slice.rb, line 24
    def slice!(*keep_keys)
      rejected = keys - keep_keys
      removed = {}
      rejected.each{ |k| removed[k] = delete(k) }
      removed
    end

stringify_keys(&select) click to toggle source

Return a new hash with all keys converted to strings. Converts all keys in the Hash to Strings, returning a new Hash. With a `select` block, limits conversion to only a certain selection of keys.

    foo = { :name=>'Gavin', :wife=>:Lisa }
    foo.stringify_keys    #=>  { "name"=>"Gavin", "wife"=>:Lisa }
    foo                   #=>  { :name =>"Gavin", :wife=>:Lisa }

This method is considered archaic. Use rekey instead.

    # File lib/facets/hash/symbolize_keys.rb, line 61
    def stringify_keys(&select)
      dup.stringify_keys!(&select)
    end

stringify_keys!(&select) click to toggle source

Destructively convert all keys to strings. This is the same as #stringify_keys, but modifies the receiver in place and returns it. With a `select` block, limits conversion to only certain keys.

    foo = { :name=>'Gavin', :wife=>:Lisa }
    foo.stringify_keys!    #=>  { "name"=>"Gavin", "wife"=>:Lisa }
    foo                    #=>  { "name"=>"Gavin", "wife"=>:Lisa }

This method is considered archaic. Use rekey instead.

    # File lib/facets/hash/symbolize_keys.rb, line 76
    def stringify_keys!(&select)
      if select
        keys.each do |key|
          if select[key]
            self[key.to_s] = delete(key)
          end
        end
      else
        keys.each do |key|
          self[key.to_s] = delete(key)
        end
      end
      self
    end

subset(keys=nil, &block) click to toggle source

Take a subset of the hash, based on keys given or a block that evaluates to true for each hash key.

    {'a'=>1, 'b'=>2}.subset('a')            #=> {'a'=>1}
    {'a'=>1, 'b'=>2}.subset{|k| k == 'a' }  #=> {'a'=>1}

CREDIT: Alexey Petrushin

    # File lib/facets/hash/subset.rb, line 10
    def subset(keys=nil, &block)
      h = {}
      if keys
        self.each do |k, v|
          h[k] = v if keys.include?(k)
        end
      else
        self.each do |k, v|
          h[k] = v if block.call(k)
        end
      end
      h
    end

swap!(key1, key2) click to toggle source

Swap the values of a pair of keys in place.

    {:a=>1,:b=>2}.swap!(:a,:b)  #=> {:a=>2,:b=>1}

CREDIT: Gavin Sinclair

    # File lib/facets/hash/swap.rb, line 9
    def swap!(key1, key2)
      tmp = self[key1]
      self[key1] = self[key2]
      self[key2] = tmp
      self
    end

symbolize_keys(&select) click to toggle source

Return a new hash with all keys converted to symbols. With a `select` block, limits conversion to only a certain selection of keys.

    foo = { :name=>'Gavin', 'wife'=>:Lisa }
    foo.symbolize_keys    #=>  { :name=>"Gavin", :wife=>:Lisa }
    foo                   #=>  { :name =>"Gavin", "wife"=>:Lisa }

If the key does not respond to to_sym, then to_s will be used first.

For a more versatile method, see rekey instead.

    # File lib/facets/hash/symbolize_keys.rb, line 18
    def symbolize_keys(&select)
      dup.symbolize_keys!(&select)
    end

symbolize_keys!(&select) click to toggle source

Destructively convert all keys to symbols. This is the same as #symbolize_keys, but modifies the receiver in place and returns it. With a `select` block, limits conversion to only selected keys.

    foo = { 'name'=>'Gavin', 'wife'=>:Lisa }
    foo.symbolize_keys!    #=>  { :name=>"Gavin", :wife=>:Lisa }
    foo                    #=>  { :name=>"Gavin", :wife=>:Lisa }

If the key does not respond to to_sym, then to_s will be used first.

For a more versatile method, see rekey instead.

    # File lib/facets/hash/symbolize_keys.rb, line 34
    def symbolize_keys!(&select)
      if select
        keys.each do |key|
          if select[key]
            new_key = (key.to_sym rescue key.to_s.to_sym)
            self[new_key] = delete(key)
          end
        end
      else
        keys.each do |key|
          new_key = (key.to_sym rescue key.to_s.to_sym)
          self[new_key] = delete(key)
        end
      end
      self
    end

to_b() click to toggle source

Boolean conversion for not empty?

    # File lib/facets/boolean.rb, line 117
    def to_b
      ! self.empty?
    end

to_h() click to toggle source

Return a rehashing of self.

    {"a"=>1,"b"=>2}.to_h  #=> {"b"=>2,"a"=>1}

CREDIT: Forian Gross

    # File lib/facets/to_hash.rb, line 211
    def to_h; rehash; end

to_hash() click to toggle source

Returns self.

    # File lib/facets/to_hash.rb, line 215
    def to_hash; self; end

to_mod(&block) click to toggle source

Convert a hash into a module.

    {:a=>1, :b=>2}.to_mod

Can take a block accepting key, value pairs which will be evaluated in the context of the module.

    h = {:a=>1, :b=>2}
    m = h.to_mod{ |k,v| module_function k }
    m.a #=> 1
    m.b #=> 2

CREDIT: Jay Fields

    # File lib/facets/hash/to_mod.rb, line 20
    def to_mod(&block)
      hash = self
      Module.new do
        hash.each do |key, value|
          define_method key do
            value #.to_object
          end
          instance_exec(key, value, &block) if block
        end
      end
    end

to_proc(response=false) click to toggle source

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

    c = Class.new do
      attr_accessor :a
    end

    h = {:a => 1}
    o = c.new
    h.to_proc.call(o)
    o.a  #=> 1

If `response` is set to `true`, then assignment will only occur if receiver responds_to? the writer method.

CREDIT: Trans

    # File lib/facets/hash/to_proc.rb, line 20
    def to_proc(response=false)
      if response
        lambda do |o|
          self.each do |k,v|
            ke = "#{k}="
            o.__send__(ke, v) if respond_to?(ke)
          end
        end
      else
        lambda do |o|
          self.each do |k,v|
            ke = "#{k}="
            o.__send__(ke, v)
          end
        end
      end
    end

to_struct(struct_name) click to toggle source

A method to convert a Hash into a Struct.

    h = {:name=>"Dan","age"=>33,"rank"=>"SrA","grade"=>"E4"}
    s = h.to_struct("Foo")

TODO: Is this robust enough considerd hashes aren't ordered?

CREDIT: Daniel Berger

    # File lib/facets/hash/to_struct.rb, line 12
    def to_struct(struct_name)
      Struct.new(struct_name,*keys).new(*values)
    end

traverse(&block) click to toggle source

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", "C"=>{"X"=>"X"}}

    g = h.traverse{ |k,v| [k.downcase, v] }

    g  #=> {"a"=>"A", "b"=>"B", "c"=>{"x"=>"X"}}

NOTE: #traverse is the same as `recursive.graph` and might be deprecated in the future (if it ever works!)

CREDIT: Trans

    # File lib/facets/hash/traverse.rb, line 18
    def traverse(&block)
      inject({}) do |h,(k,v)|
        if Hash === v
          v = v.traverse(&block)
        elsif v.respond_to?(:to_hash)
          v = v.to_hash.traverse(&block)
        end
        nk, nv = block.call(k,v)
        h[nk] = nv
        h
      end
    end

traverse!(&block) click to toggle source

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" }

CREDIT: Trans

    # File lib/facets/hash/traverse.rb, line 42
    def traverse!(&block)
      replace(traverse(&block))
    end

update_each() { || ... } click to toggle source

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

CREDIT: Trans

    # File lib/facets/hash/update_each.rb, line 10
    def update_each  # :yield:
      dup.each do |k,v|
       update(yield(k,v))
      end
      self
    end

update_keys() { || ... } click to toggle source

Iterate over hash updating just the keys.

    h = {:a=>1, :b=>2}
    h.update_keys{ |k| "#{k}!" }
    h  #=> { "a!"=>1, "b!"=>2 }

@author Trans @author Evgeniy Dolzhenko (bug fix)

    # File lib/facets/hash/update_keys.rb, line 12
    def update_keys #:yield:
      if block_given?
        keys.each { |old_key| store(yield(old_key), delete(old_key)) }
      else
        to_enum(:update_keys)
      end
    end

update_values() { || ... } click to toggle source

Iterate over hash updating just the values.

    h = {:a=>1, :b=>2}
    h.update_values{ |v| v + 1 }
    h  #=> { :a=>2, :b=>3 }

CREDIT: Trans

    # File lib/facets/hash/update_values.rb, line 11
    def update_values #:yield:
      if block_given?
        each{ |k,v| store(k, yield(v)) }
      else
        to_enum(:update_values)
      end
    end

url_params() click to toggle source

Allows for taking a hash and turning it into CGI params Since 1.8.x does not have ordered hashes the params might not be ordered.

@todo #url_params may require some URL escaping.

@author Matt Kirk

    # File lib/facets/hash/url_params.rb, line 11
    def url_params
      map do |k,v|
        if v.respond_to?(:join)
          "#{k}=#{v.join(",")}"
        else
          "#{k}=#{v}"
        end
      end.join("&")
    end

weave(h) click to toggle source

Weave is a very uniqe hash operator. I is designed to merge to complex hashes in according to sensible, regular pattern. The effect is akin to inheritance.

Two hashes are weaved together to produce a new hash. The two hashes need to be compatible according to the following rules for each node: …

    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)
    value1, value2  => value2

Here is a basic example:

    h1 = { :a => 1, :b => [ 1 ], :c => { :x => 1 } }
    h2 = { :a => 2, :b => [ 2 ], :c => { :x => 2 } }

    h1.weave(h2)
    #=> {:b=>[1, 2], :c=>{:x=>2}, :a=>2}

Weave follows the most expected pattern of unifying two complex hashes. It is especially useful for implementing overridable configuration schemes.

CREDIT: Thomas Sawyer

    # File lib/facets/hash/weave.rb, line 35
    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

|(other) click to toggle source

Operator for reverse_merge.

CREDIT: Trans

    # File lib/facets/hash/op_or.rb, line 7
    def |(other)
      other.merge(self)
    end