empty? | -> | blank? |
[] | -> | at |
Alias for fetch for greater polymorphism with Array. | ||
delete | -> | delete_at |
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 19: def self.autonew(*args) 20: #new(*args){|a,k| a[k] = self.class::new(*args)} 21: leet = lambda { |hsh, key| hsh[key] = new( &leet ) } 22: new(*args,&leet) 23: end
Instantiate a new hash with a default value determined by the block.
Hash.new_with { [] }
CREDIT: Pit Capitan
# File lib/core/facets/hash/new_with.rb, line 10 10: def self.new_with #:yield: 11: new { |h, k| h[k] = yield } 12: end
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 11: def self.zipnew(keys,values) # or some better name 12: h = {} 13: keys.size.times{ |i| h[ keys[i] ] = values[i] } 14: h 15: end
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 19: def &(other) 20: case other 21: when Array 22: k = (keys & other) 23: Hash[*(k.zip(values_at(*k)).flatten)] 24: else 25: x = (to_a & other.to_a).inject([]) do |a, kv| 26: a.concat kv; a 27: end 28: Hash[*x] 29: end 30: end
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 13: def *(other) 14: other.merge(self) 15: end
Operator for merge.
CREDIT: Trans
# File lib/core/facets/hash/op_add.rb, line 7 7: def +(other) 8: merge(other) 9: end
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 9: def -(other) 10: h = self.dup 11: if other.respond_to?(:to_ary) 12: other.to_ary.each do |k| 13: h.delete(k) 14: end 15: else 16: other.each do |k,v| 17: if h.key?(k) 18: h.delete(k) if v == h[k] 19: end 20: end 21: end 22: h 23: end
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 8: def <<(other) 9: if other.respond_to?(:to_ary) 10: self.store(*other) 11: else 12: update(other) 13: end 14: self 15: end
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 25: def alias!(newkey, oldkey) 26: self[newkey] = self[oldkey] if self.has_key?(oldkey) 27: self 28: end
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 10: def argumentize(args_field=nil) 11: config = dup 12: if args_field 13: args = [config.delete(args_field)].flatten.compact 14: else 15: args = [] 16: end 17: args << config 18: return args 19: end
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 12: def collate(other_hash) 13: h = Hash.new 14: # Prepare, ensuring every existing key is already an Array 15: each do |key, value| 16: if value.is_a?(Array) 17: h[key] = value 18: else 19: h[key] = [value] 20: end 21: end 22: # Collate with values from other_hash 23: other_hash.each do |key, value| 24: if h[key] 25: if value.is_a?(Array) 26: h[key].concat(value) 27: else 28: h[key] << value 29: end 30: elsif value.is_a?(Array) 31: h[key] = value 32: else 33: h[key] = [value] 34: end 35: end 36: #each{ |key, value| value.uniq! } if options[ :uniq ] 37: h 38: end
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 32: def dearray_singular_values 33: h = {} 34: each do |k,v| 35: case v 36: when Array 37: h[k] = (v.size < 2) ? v[0] : v 38: else 39: h[k] = v 40: end 41: end 42: h 43: end
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 11: def dearray_values(index=0) 12: h = {} 13: each do |k,v| 14: case v 15: when Array 16: h[k] = v[index] || v[-1] 17: else 18: h[k] = v 19: end 20: end 21: h 22: end
Inverse of delete_if.
CREDIT: Daniel Schierbeck
# File lib/core/facets/hash/delete.rb, line 11 11: def delete_unless #:yield: 12: delete_if{ |key, value| ! yield(key, value) } 13: end
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 24: def delete_values(*values) 25: keys.map{ |key| delete(key) if values.include?(fetch(key)) } 26: end
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 42: def delete_values_at(*keys, &yld) 43: keys.map{|key| delete(key, &yld) } 44: end
Difference comparison of two hashes.
# File lib/core/facets/hash/diff.rb, line 5 5: def diff(hash) 6: h1 = self.dup.delete_if{ |k,v| hash[k] == v } 7: h2 = hash.dup.delete_if{ |k,v| has_key?(k) } 8: h1.merge(h2) 9: end
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 40: def each_with_key( &yld ) 41: each_pair{ |k,v| yld.call(v,k) } 42: end
Returns a new hash less the given keys.
# File lib/core/facets/hash/except.rb, line 5 5: def except(*less_keys) 6: slice(*keys - less_keys) 7: end
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 18: def except!(*less_keys) 19: removed = slice(*less_keys) 20: replace(except(*less_keys)) 21: removed 22: end
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 42: def group_by_value 43: res = {} 44: each{|k, v| (res[v] ||= []) << k} 45: res 46: end
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 12: def has_keys?(*check_keys) 13: unknown_keys = check_keys - self.keys 14: return unknown_keys.empty? 15: end
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 28: def has_only_keys?(*check_keys) 29: unknown_keys = self.keys - check_keys 30: return unknown_keys.empty? 31: end
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 10: def insert(name, value) 11: if key?(name) 12: false 13: else 14: store(name,value) 15: true 16: end 17: end
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 14: def inverse 15: i = Hash.new 16: self.each_pair{ |k,v| 17: if (Array === v) 18: v.each{ |x| i[x] = ( i.has_key?(x) ? [k,i[x]].flatten : k ) } 19: else 20: i[v] = ( i.has_key?(v) ? [k,i[v]].flatten : k ) 21: end 22: } 23: return i 24: end
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 10: def mash!(&yld) 11: replace(mash(&yld)) 12: end
# File lib/core/facets/kernel/object_state.rb, line 41 41: def object_state(data=nil) 42: data ? replace(data) : dup 43: end
Same as Hash#merge but recursively merges sub-hashes.
# File lib/core/facets/hash/recursive_merge.rb, line 5 5: def recursive_merge(other) 6: hash = self.dup 7: other.each do |key, value| 8: myval = self[key] 9: if value.is_a?(Hash) && myval.is_a?(Hash) 10: hash[key] = myval.recursive_merge(value) 11: else 12: hash[key] = value 13: end 14: end 15: hash 16: end
Same as Hash#merge! but recursively merges sub-hashes.
# File lib/core/facets/hash/recursive_merge.rb, line 20 20: def recursive_merge!(other) 21: other.each do |key, value| 22: myval = self[key] 23: if value.is_a?(Hash) && myval.is_a?(Hash) 24: myval.recursive_merge!(value) 25: else 26: self[key] = value 27: end 28: end 29: self 30: end
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 10: def recursively(&block) 11: h = inject({}) do |hash, (key, value)| 12: if value.is_a?(Hash) 13: hash[key] = value.recursively(&block) 14: else 15: hash[key] = value 16: end 17: hash 18: end 19: yield h 20: end
# File lib/core/facets/hash/recursively.rb, line 24 24: def recursively!(&block) 25: replace(recursively(&block)) 26: end
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 32: def rekey(*args, &block) 33: dup.rekey!(*args, &block) 34: end
Synonym for Hash#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 44: def rekey!(*args, &block) 45: # for backward comptability (TODO: DEPRECATE). 46: block = args.pop.to_sym.to_proc if args.size == 1 47: # if no args use block. 48: if args.empty? 49: block = lambda{|k| k.to_sym} unless block 50: keys.each do |k| 51: nk = block[k] 52: self[nk]=delete(k) if nk 53: end 54: else 55: raise ArgumentError, "3 for 2" if block 56: to, from = *args 57: self[to] = self.delete(from) if self.has_key?(from) 58: end 59: self 60: end
Same as update_each, but deletes the key element first.
CREDIT: Trans
# File lib/core/facets/hash/replace_each.rb, line 7 7: def replace_each # :yield: 8: dup.each do |k,v| 9: delete(k) 10: update(yield(k,v)) 11: end 12: self 13: end
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 15: def reverse_merge(other) 16: other.merge(self) 17: end
Inplace form of reverse_merge.
# File lib/core/facets/hash/merge.rb, line 21 21: def reverse_merge!(other) 22: replace(reverse_merge(other)) 23: end
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 8: def select! 9: reject! { |k,v| not yield(k,v) } 10: end
Returns a new hash with only the given keys.
# File lib/core/facets/hash/slice.rb, line 9 9: def slice(*keep_keys) 10: h = {} 11: keep_keys.each do |key| 12: h[key] = fetch(key) 13: end 14: h 15: end
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 24: def slice!(*keep_keys) 25: removed = except(*keep_keys) 26: replace(slice(*keep_keys)) 27: removed 28: end
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 54: def stringify_keys(&filter) 55: if filter 56: rekey{ |k| filter[k] ? k.to_s : nil } 57: else 58: rekey{ |k| k.to_s } 59: end 60: end
Synonym for Hash#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 73: def stringify_keys!(&filter) 74: if filter 75: rekey!{ |k| filter[k] ? k.to_s : nil } 76: else 77: rekey!{ |k| k.to_s } 78: end 79: end
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 9: def swap!(key1, key2) 10: tmp = self[key1] 11: self[key1] = self[key2] 12: self[key2] = tmp 13: self 14: end
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 20: def symbolize_keys(&filter) 21: if filter 22: rekey{ |k| filter[k] ? k.to_sym : nil } 23: else 24: rekey{ |k| k.to_sym } 25: end 26: end
Synonym for Hash#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 37: def symbolize_keys!(&filter) 38: if filter 39: rekey!{ |k| filter[k] ? k.to_sym : nil } 40: else 41: rekey!{ |k| k.to_sym } 42: end 43: end
Return a rehashing of self.
{"a"=>1,"b"=>2}.to_h #=> {"b"=>2,"a"=>1}
CREDIT: Forian Gross
# File lib/core/facets/to_hash.rb, line 208 208: def to_h; rehash; end
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 15: def to_proc 16: lambda do |o| 17: self.each do |k,v| 18: ke = "#{k}=" 19: o.__send__(ke, v) 20: end 21: end 22: end
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 31: def to_proc_with_reponse 32: lambda do |o| 33: self.each do |k,v| 34: ke = "#{k}=" 35: o.__send__(ke, v) if respond_to?(ke) 36: end 37: end 38: end
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 12: def to_struct(struct_name) 13: Struct.new(struct_name,*keys).new(*values) 14: end
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 18: def traverse(&b) 19: inject({}) do |h,(k,v)| 20: v = ( Hash === v ? v.traverse(&b) : v ) 21: nk, nv = b[k,v] 22: h[nk] = nv #( Hash === v ? v.traverse(base,&b) : nv ) 23: h 24: end 25: end
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 36: def traverse!(&b) 37: self.replace( self.traverse(&b) ) 38: end
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 10: def update_each # :yield: 11: dup.each do |k,v| 12: update(yield(k,v)) 13: end 14: self 15: end
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 11: def update_keys #:yield: 12: if block_given? 13: keys.each { |old_key| store(yield(old_key), delete(old_key)) } 14: else 15: to_enum(:update_keys) 16: end 17: end
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 11: def update_values #:yield: 12: if block_given? 13: each{ |k,v| store(k, yield(v)) } 14: else 15: to_enum(:update_values) 16: end 17: end
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 </tt>
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 40: def weave(h) 41: raise ArgumentError, "Hash expected" unless h.kind_of?(Hash) 42: s = self.clone 43: h.each { |k,node| 44: node_is_hash = node.kind_of?(Hash) 45: node_is_array = node.kind_of?(Array) 46: if s.has_key?(k) 47: self_node_is_hash = s[k].kind_of?(Hash) 48: self_node_is_array = s[k].kind_of?(Array) 49: if self_node_is_hash 50: if node_is_hash 51: s[k] = s[k].weave(node) 52: elsif node_is_array 53: raise ArgumentError, 'Incompatible hash addition' #self[k] = node 54: else 55: raise ArgumentError, 'Incompatible hash addition' #self[k] = node 56: end 57: elsif self_node_is_array 58: if node_is_hash 59: raise ArgumentError, 'Incompatible hash addition' #self[k] = node 60: elsif node_is_array 61: s[k] += node 62: else 63: s[k] << node 64: end 65: else 66: if node_is_hash 67: raise ArgumentError, 'Incompatible hash addition' #self[k] = node 68: elsif node_is_array 69: s[k].unshift( node ) 70: else 71: s[k] = node 72: end 73: end 74: else 75: s[k] = node 76: end 77: } 78: s 79: end
Operator for reverse_merge.
CREDIT: Trans
# File lib/core/facets/hash/op_or.rb, line 7 7: def |(other) 8: other.merge(self) 9: end