class Hash

Public Class Methods

autonew(*args) click to toggle source
Hash which auto initializes it's children.

 ah = Hash.autonew
 ah['section one']['param one'] = 4
 ah['section one']['param two'] = 5
 ah['section one']['param three'] = 2
 ah['section one']['param four'] = 3

 p ah
 # {"section one"=>{"param one"=>4, "param four"=>3, "param three"=>2, "param two"=>5}}

 p ah['section one'].keys
 # ["param one", "param four", "param three", "param two"]

CREDIT: Trans, Jan Molic

# File lib/core/facets/hash/autonew.rb, line 19
def self.autonew(*args)
  #new(*args){|a,k| a[k] = self.class::new(*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/core/facets/hash/new_with.rb, line 10
def self.new_with #:yield:
  new { |h, k| h[k] = yield }
end
zipnew(keys,values) click to toggle source

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 }

CREDIT: Trans, Ara T. Howard

# File lib/core/facets/hash/zipnew.rb, line 11
def self.zipnew(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/core/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/core/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/core/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

# File lib/core/facets/hash/op_sub.rb, line 9
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/core/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/core/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 arguments.

h = { :list => [1,2], :base => "HI" }
h.argumentize #=> [ [], { :list => [1,2], :base => "HI" } ]
h.argumentize(:list)   #=> [ [1,2], { :base => "HI" } ]
h.argumentize(:base)   #=> [ ["HI"], { :list => [1,2] } ]
# File lib/core/facets/hash/argumentize.rb, line 10
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_hash) 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] }

CREDIT: Tilo Sloboda CREDIT: Gavin Kistner (Phrogz)

# File lib/core/facets/hash/collate.rb, line 12
def collate(other_hash)
  h = Hash.new
  # Prepare, ensuring every existing key is already an Array
  each do |key, value|
    if value.is_a?(Array)
      h[key] = value
    else
      h[key] = [value]
    end
  end
  # Collate with values from other_hash
  other_hash.each do |key, value|
    if h[key]
      if value.is_a?(Array)
        h[key].concat(value)
      else
        h[key] << value
      end
    elsif value.is_a?(Array)
      h[key] = value
    else
      h[key] = [value]
    end
  end
  #each{ |key, value| value.uniq! } if options[ :uniq ]
  h
end
collate!(other_hash) click to toggle source

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

# File lib/core/facets/hash/collate.rb, line 42
def collate!(other_hash)
  result = self.collate(other_hash)
  self.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/core/facets/hash/count.rb, line 9
def count(value)
  values.count(value)
end
data() click to toggle source

TODO: The name of this method may change.

# File lib/core/facets/hash/data.rb, line 7
def data
  Functor.new() do |op| 
    self[op]
  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/core/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/core/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
delete_unless() { || ... } click to toggle source

Inverse of delete_if.

CREDIT: Daniel Schierbeck

# File lib/core/facets/hash/delete.rb, line 11
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 }

CREDIT: Daniel Schierbeck

# File lib/core/facets/hash/delete.rb, line 24
def delete_values(*values)
  keys.map{ |key| delete(key) if values.include?(fetch(key)) }
end
delete_values_at(*keys, &yld) click to toggle source

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

This works niely with hash#[] and Hash#[]= facets.

hsh[:a, :b, :c] = 1, 2, 3

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

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

CREDIT: Daniel Schierbeck

# File lib/core/facets/hash/delete.rb, line 42
def delete_values_at(*keys, &yld)
  keys.map{|key| delete(key, &yld) }
end
diff(hash) click to toggle source

Difference comparison of two hashes.

# File lib/core/facets/hash/diff.rb, line 5
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/core/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/core/facets/hash/except.rb, line 5
def except(*less_keys)
  slice(*keys - less_keys)
end
except!(*less_keys) 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}
# File lib/core/facets/hash/except.rb, line 18
def except!(*less_keys)
  removed = slice(*less_keys)
  replace(except(*less_keys))
  removed
end
graph!(&yld) click to toggle source

Alias for mash!. This is the original name for this method.

Alias for: mash!
group_by_value() click to toggle source

Like group_by, but allows hash values to be grouped with weeding out the keys.

Example:

birthdays = {...}   # Maps each person to his/her birthday.

Now I want to have the list of people that have their birthday on a specific date. This can be done by creating a hash first, using group_by:

birthdays.group_by{|person, birthday| birthday}

This returns:

{date=>[[person1, date], [person2, date], [person3, date]]}

... which is a bit inconvient. Too many dates. I would rather like to have:

{date=>[person1, person2, person3]]}

This can be achieved by:

birthdays.inject!({}){|h, (person, date)| (h[date] ||= []) << person}

I've used this pattern just once too often, so I moved the code to Hash (and Enumerable, for associative arrays). Here's the cleaner code:

birthdays.group_by_value

h = {"A"=>1, "B"=>1, "C"=>1, "D"=>2, "E"=>2, "F"=>2, "G"=>3, "H"=>3, "I"=>3}

h.group_by{|k, v| v}    # ==> {1=>[["A", 1], ["B", 1], ["C", 1]], 2=>[["D", 2], ["E", 2], ["F", 2]], 3=>[["G", 3], ["H", 3], ["I", 3]]}
h.group_by_value        # ==> {1=>["A", "B", "C"], 2=>["D", "E", "F"], 3=>["G", "H", "I"]}
h.sort.group_by_value   # ==> [[1, ["A", "B", "C"]], [2, ["D", "E", "F"]], [3, ["G", "H", "I"]]]

CREDIT: Erik Veenstra

# File lib/core/facets/hash/group_by_value.rb, line 42
def group_by_value
  res = {}
  each{|k, v| (res[v] ||= []) << k}
  res
end
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/core/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/core/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/core/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}
h.inverse.inverse == h  #=> true

CREDIT: Tilo Sloboda

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

Like Array#join but specialized to Hash.

CREDIT: Mauricio Fernandez

# File lib/core/facets/hash/join.rb, line 7
def join(pair_divider='', elem_divider='')
  s = []
  each_pair { |k,v| s << "#{k}#{pair_divider}#{v}" }
  s.join(elem_divider)
end
keys?(*check_keys) click to toggle source
Alias for: has_keys?
mash!(&yld) click to toggle source

In place version of mash.

NOTE: Hash#mash! is only useful for Hash. It is not generally
      applicable to Enumerable.
# File lib/core/facets/hash/mash.rb, line 10
def mash!(&yld)
  replace(mash(&yld))
end
Also aliased as: graph!
object_state(data=nil) click to toggle source
# File lib/core/facets/kernel/object_state.rb, line 43
def object_state(data=nil)
  data ? replace(data) : dup
end
only_keys?(*check_keys) click to toggle source
Alias for: has_only_keys?
recursive_merge(other) click to toggle source

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

# File lib/core/facets/hash/recursive_merge.rb, line 5
def recursive_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.recursive_merge(value)
    else
      hash[key] = value
    end
  end
  hash
end
recursive_merge!(other) click to toggle source

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

# File lib/core/facets/hash/recursive_merge.rb, line 20
def recursive_merge!(other)
  other.each do |key, value|
    myval = self[key]
    if value.is_a?(Hash) && myval.is_a?(Hash)
      myval.recursive_merge!(value)
    else
      self[key] = value
    end
  end
  self
end
recursively() { |h| ... } click to toggle source

Apply a block to hash, and recursively apply that block to each subhash.

h = {:a=>1, :b=>{:b1=>1, :b2=>2}}
h.recursively{|h| h.rekey(&:to_s) }
=> {"a"=>1, "b"=>{"b1"=>1, "b2"=>2}}
# File lib/core/facets/hash/recursively.rb, line 10
def recursively(&block)
  h = inject({}) do |hash, (key, value)|
    if value.is_a?(Hash)
      hash[key] = value.recursively(&block)
    else
      hash[key] = value
    end
    hash
  end
  yield h
end
recursively!(&block) click to toggle source
# File lib/core/facets/hash/recursively.rb, line 24
def recursively!(&block)
  replace(recursively(&block))
end
rekey(*args, &block) click to toggle source

Rekey a hash.

rekey()
rekey(to_key, from_key)
rekey{ |key| ... }

If no arguments or block are given, then all keys are converted to Symbols.

If two keys are given, then the second key is changed to the first. You can think of it as alias for hash keys.

foo = { :a=>1, :b=>2 }
foo.rekey('a',:a)       #=> { 'a'=>1, :b=>2 }
foo.rekey('b',:b)       #=> { 'a'=>1, 'b'=>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. If the block returns nil for 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.inspect              #=>  { :name =>"Gavin", :wife=>:Lisa }

CREDIT: Trans, Gavin Kistner

# File lib/core/facets/hash/rekey.rb, line 32
def rekey(*args, &block)
  dup.rekey!(*args, &block)
end
rekey!(*args, &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.inspect               #=>  { "name"=>"Gavin", "wife"=>:Lisa }

CREDIT: Trans, Gavin Kistner

# File lib/core/facets/hash/rekey.rb, line 44
def rekey!(*args, &block)
  # for backward comptability (TODO: DEPRECATE).
  block = args.pop.to_sym.to_proc if args.size == 1
  # if no args use block.
  if args.empty?
    block = lambda{|k| k.to_sym} unless block
    keys.each do |k|
      nk = block[k]
      self[nk]=delete(k) if nk
    end
  else
    raise ArgumentError, "3 for 2" if block
    to, from = *args
    self[to] = self.delete(from) if self.has_key?(from)
  end
  self
end
replace_each() { || ... } click to toggle source

Same as update_each, but deletes the key element first.

CREDIT: Trans

# File lib/core/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/core/facets/hash/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/core/facets/hash/merge.rb, line 21
def reverse_merge!(other)
  replace(reverse_merge(other))
end
Also aliased as: reverse_update
reverse_update(other) click to toggle source

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/core/facets/hash/select.rb, line 8
def select!
  reject! { |k,v| not yield(k,v) }
end
shelljoin() click to toggle source
# File lib/more/facets/shellwords.rb, line 57
def shelljoin
  shellwords.shelljoin
end
shellwords() click to toggle source
# File lib/more/facets/shellwords.rb, line 37
def shellwords
  argv = []
  each do |f,v|
    m = f.to_s.size == 1 ? '-' : '--'
    case v
    when false, nil
    when Array
      v.each do |e|
        argv << %Q[#{m}#{f}="#{e}"]
      end
    when true
      argv << %Q[#{m}#{f}]
    else
      argv << %Q[#{m}#{f}="#{v}"]
    end
  end
  argv
end
slice(*keep_keys) click to toggle source

Returns a new hash with only the given keys.

# File lib/core/facets/hash/slice.rb, line 9
def slice(*keep_keys)
  h = {}
  keep_keys.each do |key|
    h[key] = fetch(key)
  end
  h
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)  #=> {:a=>1}
h             #=> {:b=>2}
# File lib/core/facets/hash/slice.rb, line 24
def slice!(*keep_keys)
  removed = except(*keep_keys)
  replace(slice(*keep_keys))
  removed
end
stringify_keys(&filter) click to toggle source

Converts all keys in the Hash to Strings, returning a new Hash. With a filter parameter, limits conversion to only a certain selection of keys.

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

This method is considered archaic. Use rekey instead.

# File lib/core/facets/hash/symbolize_keys.rb, line 54
def stringify_keys(&filter)
  if filter
    rekey{ |k| filter[k] ? k.to_s : nil }
  else
    rekey{ |k| k.to_s }
  end
end
stringify_keys!(&filter) click to toggle source

Synonym for #stringify_keys, but modifies the receiver in place and returns it. With a filter parameter, limits conversion to only a certain selection of keys.

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

This method is considered archaic. Use rekey instead.

# File lib/core/facets/hash/symbolize_keys.rb, line 73
def stringify_keys!(&filter)
  if filter
    rekey!{ |k| filter[k] ? k.to_s : nil }
  else
    rekey!{ |k| k.to_s }
  end
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/core/facets/hash/swap.rb, line 9
def swap!(key1, key2)
  tmp = self[key1]
  self[key1] = self[key2]
  self[key2] = tmp
  self
end
symbolize_keys(&filter) click to toggle source

Converts all keys in the Hash to Symbols, returning a new Hash. With a filter, limits conversion to only a certain selection of keys.

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

This method is considered archaic. Use rekey instead.

# File lib/core/facets/hash/symbolize_keys.rb, line 20
def symbolize_keys(&filter)
  if filter
    rekey{ |k| filter[k] ? k.to_sym : nil }
  else
    rekey{ |k| k.to_sym }
  end
end
symbolize_keys!(&filter) click to toggle source

Synonym for #symbolize_keys, but modifies the receiver in place and returns it. With a filter parameter, limits conversion to only a certain selection of keys.

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

This method is considered archaic. Use rekey instead.

# File lib/core/facets/hash/symbolize_keys.rb, line 37
def symbolize_keys!(&filter)
  if filter
    rekey!{ |k| filter[k] ? k.to_sym : nil }
  else
    rekey!{ |k| k.to_sym }
  end
end
to_openobject() click to toggle source

Convert a Hash into an OpenObject.

# File lib/more/facets/openobject.rb, line 241
def to_openobject
  OpenObject[self]
end
to_ostruct() click to toggle source

Turns a hash into a generic object using an OpenStruct.

o = { 'a' => 1 }.to_ostruct
o.a  #=> 1
# File lib/more/facets/ostruct.rb, line 200
def to_ostruct
  OpenStruct.new(self)
end
to_ostruct_recurse(exclude={}) click to toggle source

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

CREDIT: Alison Rowland, Jamie Macey, Mat Schaffer

# File lib/more/facets/ostruct.rb, line 221
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() 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.

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

CREDIT: Trans

# File lib/core/facets/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() click to toggle source

A fault-tolerent version of to_proc.

It works just like to_proc, but the block will make sure# the object responds to the assignment.

CREDIT: Trans

# File lib/core/facets/hash/to_proc.rb, line 31
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
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/core/facets/hash/to_struct.rb, line 12
def to_struct(struct_name)
  Struct.new(struct_name,*keys).new(*values)
end
traverse(&b) 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" }
g = h.traverse { |k,v| [k.downcase, v] }
g  #=> { "a"=>"A", "b"=>"B" }

TODO: Contrast these to recursibely --we may not need both.

TODO: Testing value to see if it is a Hash also catches subclasses of Hash.

This is probably not the right thing to do and should catch Hashes only (?)

CREDIT: Trans

# File lib/core/facets/hash/traverse.rb, line 18
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) 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/core/facets/hash/traverse.rb, line 36
def traverse!(&b)
  self.replace( self.traverse(&b) )
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/core/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 }

CREDIT: Trans

# File lib/core/facets/hash/update_keys.rb, line 11
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/core/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
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:

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

Here is a basic example:

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

h2 = { :a => 2, :b => [ 2 ], :c => { :x => 2 } }
=> {:b=>[2], :c=>{:x=>2}, :a=>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/core/facets/hash/weave.rb, line 40
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/core/facets/hash/op_or.rb, line 7
def |(other)
  other.merge(self)
end