Class: Hash
- Includes:
- Random::HashExtensions, URI::Hash
- Defined in:
- lib/standard/facets/uri.rb,
lib/core/facets/boolean.rb,
lib/core/facets/hash/at.rb,
lib/core/facets/hash/zip.rb,
lib/core/facets/hash/data.rb,
lib/core/facets/hash/diff.rb,
lib/core/facets/hash/join.rb,
lib/core/facets/hash/keys.rb,
lib/core/facets/hash/swap.rb,
lib/core/facets/hash/alias.rb,
lib/core/facets/hash/count.rb,
lib/core/facets/hash/graph.rb,
lib/core/facets/hash/op_or.rb,
lib/core/facets/hash/rekey.rb,
lib/core/facets/hash/slice.rb,
lib/core/facets/hash/weave.rb,
lib/core/facets/hash/except.rb,
lib/core/facets/hash/insert.rb,
lib/core/facets/hash/op_add.rb,
lib/core/facets/hash/op_and.rb,
lib/core/facets/hash/op_mul.rb,
lib/core/facets/hash/op_sub.rb,
lib/core/facets/hash/subset.rb,
lib/core/facets/hash/to_mod.rb,
lib/core/facets/hash/autonew.rb,
lib/core/facets/hash/collate.rb,
lib/core/facets/hash/inverse.rb,
lib/core/facets/hash/op_push.rb,
lib/core/facets/hash/recurse.rb,
lib/core/facets/hash/revalue.rb,
lib/core/facets/hash/to_proc.rb,
lib/core/facets/kernel/blank.rb,
lib/core/facets/hash/new_with.rb,
lib/core/facets/hash/traverse.rb,
lib/core/facets/hash/delete_at.rb,
lib/core/facets/hash/to_struct.rb,
lib/core/facets/hash/deep_merge.rb,
lib/core/facets/hash/deep_rekey.rb,
lib/core/facets/hash/argumentize.rb,
lib/core/facets/hash/recursively.rb,
lib/core/facets/hash/update_each.rb,
lib/core/facets/hash/update_keys.rb,
lib/core/facets/hash/fetch_nested.rb,
lib/core/facets/hash/replace_each.rb,
lib/core/facets/hash/delete_unless.rb,
lib/core/facets/hash/delete_values.rb,
lib/core/facets/hash/each_with_key.rb,
lib/core/facets/hash/reverse_merge.rb,
lib/core/facets/hash/update_values.rb,
lib/core/facets/hash/dearray_values.rb,
lib/core/facets/hash/symbolize_keys.rb,
lib/core/facets/object/object_state.rb,
lib/core/facets/array/extract_options.rb,
lib/standard/facets/random.rb,
lib/standard/facets/shellwords.rb,
lib/standard/facets/ostruct/to_ostruct.rb
Overview
:nodoc:
Direct Known Subclasses
Defined Under Namespace
Classes: Recursor
Class Method Summary collapse
-
.autonew(*args) ⇒ Object
Hash which auto initializes it’s children.
-
.new_with ⇒ Object
Instantiate a new hash with a default value determined by the block.
-
.zip(keys, values) ⇒ Object
Creates a new hash from two separate arrays, a
keys
array and avalues
array.
Instance Method Summary collapse
-
#&(other) ⇒ Object
Hash intersection.
-
#*(other) ⇒ Object
Like merge operator ‘+’ but merges in reverse order.
-
#+(other) ⇒ Object
Operator for #merge.
-
#-(other) ⇒ Object
Operator for removing hash pairs.
-
#<<(other) ⇒ Object
Can be used like update, or passed as two-element [key,value] array.
-
#alias!(newkey, oldkey) ⇒ Object
Modifies the receiving Hash so that the value previously referred to by oldkey is also referenced by newkey; oldkey is retained in the Hash.
-
#argumentize(args_field = nil) ⇒ Object
Turn a hash into a method arguments.
-
#collate(*others) ⇒ Object
Merge the values of this hash with those from another, setting all values to be arrays representing the values from both hashes.
-
#collate!(other_hash) ⇒ Object
The same as #collate, but modifies the receiver in place.
-
#count(*value) ⇒ Object
Like Enumerable#count, but can count hash values.
-
#data ⇒ Object
Access to a hash as if it were an OpenStruct.
-
#dearray_singular_values ⇒ Object
Any array values with one or no elements will be set to the element or nil.
-
#dearray_values(index = 0) ⇒ Object
Any array values will be replaced with the first element of the array.
-
#deep_merge(other) ⇒ Object
Same as Hash#merge but recursively merges sub-hashes.
-
#deep_merge!(other) ⇒ Object
Same as Hash#merge! but recursively merges sub-hashes.
-
#deep_rekey(key_map = nil, &block) ⇒ Object
Rekey a hash and all sub-hashes:.
-
#deep_rekey!(key_map = nil, &block) ⇒ Object
Synonym for Hash#deep_rekey, but modifies the receiver in place (and returns it).
-
#delete_unless ⇒ Object
Inverse of #delete_if.
-
#delete_values(*values) ⇒ Object
Minor modification to Ruby’s Hash#delete method allowing it to take multiple keys.
-
#delete_values_at(*keys, &yld) ⇒ Object
Minor modification to Ruby’s Hash#delete method allowing it to take multiple keys.
-
#diff(hash) ⇒ Object
Difference comparison of two hashes.
-
#each_with_key(&yld) ⇒ Object
Each with key is like each_pair but reverses the order the parameters to [value,key] instead of [key,value].
-
#except(*less_keys) ⇒ Object
Returns a new hash less the given keys.
-
#except!(*rejected) ⇒ Object
Replaces hash with new hash less the given keys.
-
#extractable_options? ⇒ Boolean
By default, only instances of Hash itself are extractable.
-
#fetch_nested(*keys) ⇒ Object
Similar to Hash#fetch but supports nested lookup and is ‘nil` safe.
-
#graph!(&yld) ⇒ Object
(also: #mash!)
In place version of #graph.
-
#insert(name, value) ⇒ Object
As with #store but only if the key isn’t already in the hash.
-
#inverse ⇒ Object
Create a “true” inverse hash by storing mutliple values in Arrays.
-
#join(pair_divider = '', elem_divider = nil) ⇒ Object
Like Array#join but specialized to Hash.
-
#keys?(*check_keys) ⇒ Boolean
(also: #has_keys?)
Returns true or false whether the hash contains the given keys.
- #object_state(data = nil) ⇒ Object
-
#only_keys?(*check_keys) ⇒ Boolean
(also: #has_only_keys?)
Returns true if the hash contains only the given keys, otherwise false.
-
#recurse(*types) {|h| ... } ⇒ Object
Apply a block to hash, and recursively apply that block to each sub-hash or
types
. -
#recurse!(&block) ⇒ Object
In place form of #recurse.
-
#recursively(*types, &block) ⇒ Object
Apply a block to a hash, and recursively apply that block to each sub-hash:.
-
#rekey(key_map = nil, &block) ⇒ Object
Rekey a hash:.
-
#rekey!(key_map = nil, &block) ⇒ Object
Synonym for Hash#rekey, but modifies the receiver in place (and returns it).
-
#remove!(*rejected) ⇒ Object
Replaces hash with new hash less the given keys.
-
#replace_each ⇒ Object
Same as #update_each, but deletes the key element first.
-
#revalue(val_map = nil, &block) ⇒ Object
Generates a new hash where the values are the result of the passed in block.
-
#revalue!(val_map = nil, &block) ⇒ Object
The in-place version of Hash#revalue.
-
#reverse_merge(other) ⇒ Object
Allows for reverse merging where its the keys in the calling hash that wins over those in the
other_hash
. -
#reverse_merge!(other) ⇒ Object
(also: #reverse_update)
Inplace form of #reverse_merge.
- #shelljoin ⇒ Object
- #shellwords ⇒ Object
-
#slice(*keep_keys) ⇒ Object
Returns a new hash with only the given keys.
-
#slice!(*keep_keys) ⇒ Object
Replaces hash with a new hash having only the given keys.
-
#stringify_keys(&select) ⇒ Object
Return a new hash with all keys converted to strings.
-
#stringify_keys!(&select) ⇒ Object
Destructively convert all keys to strings.
-
#subset(*keys, &block) ⇒ Object
Take a subset of the hash, based on keys given or a block that evaluates to true for each hash key.
-
#swap!(key1, key2) ⇒ Object
Swap the values of a pair of keys in place.
-
#symbolize_keys(&select) ⇒ Object
Return a new hash with all keys converted to symbols.
-
#symbolize_keys!(&select) ⇒ Object
Destructively convert all keys to symbols.
-
#to_b ⇒ Object
Boolean conversion for not empty?.
-
#to_mod(&block) ⇒ Object
Convert a hash into a module.
-
#to_ostruct ⇒ Object
Turns a hash into a generic object using an OpenStruct.
-
#to_ostruct_recurse(exclude = {}) ⇒ Object
Like ‘#to_ostruct` but recusively objectifies all hash elements as well.
-
#to_proc(response = false) ⇒ Object
Constructs a Proc object from a hash such that the parameter of the Proc is assigned the hash keys as attributes.
-
#to_struct(struct_name) ⇒ Object
A method to convert a Hash into a Struct.
-
#traverse(&block) ⇒ Object
Returns a new hash created by traversing the hash and its subhashes, executing the given block on the key and value.
-
#traverse!(&block) ⇒ Object
In place version of traverse, which traverses the hash and its subhashes, executing the given block on the key and value.
-
#update_each ⇒ Object
Iterates through each pair and updates the hash in place.
-
#update_keys ⇒ Object
Iterate over hash updating just the keys.
-
#update_values ⇒ Object
Iterate over hash updating just the values.
-
#weave(h) ⇒ Object
Weave is a very unique hash operator.
-
#|(other) ⇒ Object
Operator for #reverse_merge.
Methods included from Random::HashExtensions
#rand_key, #rand_key!, #rand_pair, #rand_pair!, #rand_value, #rand_value!, #shuffle, #shuffle!
Methods included from URI::Hash
Class Method Details
.autonew(*args) ⇒ Object
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
18 19 20 21 |
# File 'lib/core/facets/hash/autonew.rb', line 18 def self.autonew(*args) leet = lambda{ |hsh, key| hsh[key] = new( &leet ) } new(*args,&leet) end |
.new_with ⇒ Object
Instantiate a new hash with a default value determined by the block.
Hash.new_with{ [] }
CREDIT: Pit Capitan
10 11 12 |
# File 'lib/core/facets/hash/new_with.rb', line 10 def self.new_with #:yield: new { |h, k| h[k] = yield } end |
.zip(keys, values) ⇒ Object
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
11 12 13 14 15 |
# File 'lib/core/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 |
Instance Method Details
#&(other) ⇒ Object
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
19 20 21 22 23 24 25 26 27 28 29 30 |
# 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) ⇒ Object
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
13 14 15 |
# File 'lib/core/facets/hash/op_mul.rb', line 13 def *(other) other.merge(self) end |
#+(other) ⇒ Object
Operator for #merge.
CREDIT: Trans
7 8 9 |
# File 'lib/core/facets/hash/op_add.rb', line 7 def +(other) merge(other) end |
#-(other) ⇒ Object
Operator for removing hash pairs. 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)
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
# File 'lib/core/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) ⇒ Object
Can be used like update, or passed as two-element [key,value] array.
CREDIT: Trans
8 9 10 11 12 13 14 15 |
# File 'lib/core/facets/hash/op_push.rb', line 8 def <<(other) if other.respond_to?(:to_ary) store(*other) else update(other) end self end |
#alias!(newkey, oldkey) ⇒ Object
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.
25 26 27 28 |
# 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) ⇒ Object
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] } ]
16 17 18 19 20 21 22 23 24 25 |
# File 'lib/core/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(*others) ⇒ Object
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] }
As of v3.0, this method no longer automatically flattens the array values. To acheive the same effect add a flat map.
h = { :a=>[1,3], :b=>[2,4], :c=>[5] }.collate(:a=>6, :b=>7, :c=>8)
h.each_value{ |v| v.flatten! }
#=> { :a=>[1,3,6], :b=>[2,4,7], :c=>[5,8] }
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
# File 'lib/core/facets/hash/collate.rb', line 20 def collate(*others) h = {} keys.each do |k| h[k] = [] end others.each do |other| other.keys.each do |k| h[k] = [] end end each do |k, v| h[k] << v end others.each do |other| other.each do |k, v| h[k] << v end end h.each{ |k,v| v.flatten! } h end |
#collate!(other_hash) ⇒ Object
The same as #collate, but modifies the receiver in place.
43 44 45 46 |
# File 'lib/core/facets/hash/collate.rb', line 43 def collate!(other_hash) result = collate(other_hash) replace(result) end |
#count(*value) ⇒ Object
Like Enumerable#count, but can count hash values.
{:A=>1, :B=>1}.count(1) #=> 2
7 8 9 10 11 12 13 |
# File 'lib/core/facets/hash/count.rb', line 7 def count(*value) if value.empty? super() else values.count(*value) end end |
#data ⇒ Object
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: Is there a better name for ‘data` –perhaps `open`?
TODO: Is this method really worth having?
Returns [Functor].
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/core/facets/hash/data.rb', line 25 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 ⇒ Object
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
32 33 34 35 36 37 38 39 40 41 42 43 |
# 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) ⇒ Object
Any array values will 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
11 12 13 14 15 16 17 18 19 20 21 22 |
# 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 |
#deep_merge(other) ⇒ Object
Same as Hash#merge but recursively merges sub-hashes.
5 6 7 8 9 10 11 12 13 14 15 16 |
# File 'lib/core/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) ⇒ Object
Same as Hash#merge! but recursively merges sub-hashes.
20 21 22 23 24 25 26 27 28 29 30 |
# File 'lib/core/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 |
#deep_rekey(key_map = nil, &block) ⇒ Object
Rekey a hash and all sub-hashes:
deep_rekey()
deep_rekey(from_key => to_key, ...)
deep_rekey{|from_key| to_key}
deep_rekey{|from_key, value| to_key}
If a key map is given, then the first key is changed to the second key.
foo = { :c=>{ :a=>1, :b=>2 } }
foo.deep_rekey(:a=>'a') #=> { :c=>{ 'a'=>1, :b=>2 } }
foo.deep_rekey(:b=>:x) #=> { :c=>{ :a =>1, :x=>2 } }
foo.deep_rekey('foo'=>'bar') #=> { :c=>{ :a =>1, :b=>2 } }
If a block is given, converts all keys in the Hash accroding to the given block procedure.
foo = { :person=>{ :name=>'Gavin', :wife=>:Lisa } }
foo.deep_rekey{ |k| k.to_s } #=> { "person"=>{ "name"=>"Gavin", "wife"=>:Lisa } }
foo #=> { "person"=>{ "name"=>"Gavin", "wife"=>:Lisa } }
If no key map or block is given, then all keys are converted to Symbols.
Raises an ArgumentError if both a key_map
and a block are given. If both are needed just call #deep_rekey twice.
TODO: If ‘nil` is returned by block should the key be set to `nil` or the orignal key?
CREDIT: Trans, Gavin Kistner, Ryan Duryea
37 38 39 40 41 |
# File 'lib/core/facets/hash/deep_rekey.rb', line 37 def deep_rekey(key_map=nil, &block) recurse do |h| h.rekey(key_map, &block) end end |
#deep_rekey!(key_map = nil, &block) ⇒ Object
Synonym for Hash#deep_rekey, but modifies the receiver in place (and returns it).
foo = { :person=>{ :name=>'Gavin', :wife=>:Lisa } }
foo.deep_rekey!{ |k| k.to_s } #=> { "person"=>{ "name"=>"Gavin", "wife"=>:Lisa } }
foo #=> { "person"=>{ "name"=>"Gavin", "wife"=>:Lisa } }
CREDIT: Trans, Gavin Kistner, Ryan Duryea
51 52 53 |
# File 'lib/core/facets/hash/deep_rekey.rb', line 51 def deep_rekey!(key_map=nil, &block) replace(deep_rekey(key_map, &block)) end |
#delete_unless ⇒ Object
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
12 13 14 |
# File 'lib/core/facets/hash/delete_unless.rb', line 12 def delete_unless #:yield: delete_if{ |key, value| ! yield(key, value) } end |
#delete_values(*values) ⇒ Object
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
14 15 16 17 18 19 20 21 22 23 |
# File 'lib/core/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) ⇒ Object
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
37 38 39 |
# File 'lib/core/facets/hash/delete_values.rb', line 37 def delete_values_at(*keys, &yld) keys.map{|key| delete(key, &yld) } end |
#diff(hash) ⇒ Object
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}
11 12 13 14 15 |
# File 'lib/core/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) ⇒ Object
Each with key is like each_pair but reverses the order the parameters to [value,key] instead of [key,value].
CREDIT: Trans
8 9 10 |
# File 'lib/core/facets/hash/each_with_key.rb', line 8 def each_with_key( &yld ) each_pair{ |k,v| yld.call(v,k) } end |
#except(*less_keys) ⇒ Object
Returns a new hash less the given keys.
4 5 6 7 8 |
# File 'lib/core/facets/hash/except.rb', line 4 def except(*less_keys) hash = dup less_keys.each{ |k| hash.delete(k) } hash end |
#except!(*rejected) ⇒ Object
Replaces hash with new hash less the given keys.
h = {:a=>1, :b=>2, :c=>3}
h.except!(:a) #=> {:b=>2,:c=>3}
h #=> {:b=>2,:c=>3}
Returns the hash.
17 18 19 20 |
# File 'lib/core/facets/hash/except.rb', line 17 def except!(*rejected) rejected.each{ |k| delete(k) } self end |
#extractable_options? ⇒ Boolean
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.
7 8 9 |
# File 'lib/core/facets/array/extract_options.rb', line 7 def instance_of?(Hash) end |
#fetch_nested(*keys) ⇒ Object
Similar to Hash#fetch but supports nested lookup and is ‘nil` safe.
{}.fetch_nested('anything','at','all') #=> nil
h = {'hello'=>{'world'=>42}}
h.fetch_nested(*['hello','world']) #=> 42
CREDIT: T. Yamada and Sean Mackesey
12 13 14 15 16 17 18 |
# File 'lib/core/facets/hash/fetch_nested.rb', line 12 def fetch_nested(*keys) begin keys.reduce(self){|accum, k| accum.fetch(k)} rescue (RUBY_VERSION<'1.9' ? IndexError : KeyError) block_given? ? yield(*keys) : nil end end |
#graph!(&yld) ⇒ Object Also known as: mash!
In place version of #graph.
NOTE: Hash#graph! is only useful for Hash. It is not generally applicable to Enumerable.
10 11 12 |
# File 'lib/core/facets/hash/graph.rb', line 10 def graph!(&yld) replace(graph(&yld)) end |
#insert(name, value) ⇒ Object
As with #store but only if the key isn’t already in the hash.
TODO: Would #store? be a better name?
CREDIT: Trans
10 11 12 13 14 15 16 17 |
# 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 ⇒ Object
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
17 18 19 20 21 22 23 24 25 26 27 |
# File 'lib/core/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) ⇒ Object
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
10 11 12 13 14 15 |
# File 'lib/core/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) ⇒ Boolean Also known as: has_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
CREDIT: Trans
12 13 14 15 |
# File 'lib/core/facets/hash/keys.rb', line 12 def keys?(*check_keys) unknown_keys = check_keys - self.keys return unknown_keys.empty? end |
#object_state(data = nil) ⇒ Object
61 62 63 |
# File 'lib/core/facets/object/object_state.rb', line 61 def object_state(data=nil) data ? replace(data) : dup end |
#only_keys?(*check_keys) ⇒ Boolean Also known as: has_only_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
CREDIT: Trans
28 29 30 31 |
# File 'lib/core/facets/hash/keys.rb', line 28 def only_keys?(*check_keys) unknown_keys = self.keys - check_keys return unknown_keys.empty? end |
#recurse(*types) {|h| ... } ⇒ Object
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}}
10 11 12 13 14 15 16 17 18 19 20 21 22 |
# File 'lib/core/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) ⇒ Object
In place form of #recurse.
25 26 27 |
# File 'lib/core/facets/hash/recurse.rb', line 25 def recurse!(&block) replace(recurse(&block)) end |
#recursively(*types, &block) ⇒ Object
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"]]]]
20 21 22 |
# File 'lib/core/facets/hash/recursively.rb', line 20 def recursively(*types, &block) Recursor.new(self, *types, &block) end |
#rekey(key_map = nil, &block) ⇒ Object
Rekey a hash:
rekey()
rekey(from_key => to_key, ...)
rekey{|from_key| to_key}
rekey{|from_key, value| 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.
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.
Raises an ArgumentError if both a key_map
and a block are given. If both are needed just call #rekey twice.
TODO: If ‘nil` is returned by block should the key be set to `nil` or the orignal key?
CREDIT: Trans, Gavin Kistner
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/core/facets/hash/rekey.rb', line 34 def rekey(key_map=nil, &block) raise ArgumentError, "argument or block" if key_map && block if !(key_map or block) block = lambda{|k| k.to_sym} end if block hash = dup.clear if block.arity.abs == 1 each_pair do |k, v| hash[block[k]] = v #hash[block[k] || k] = v end else each_pair do |k, v| hash[block[k,v]] = v #hash[block[k,v] || k] = v end end else #hash = dup.clear # 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 hash = dup # to keep default_proc key_map.each_pair do |from, to| hash[to] = hash.delete(from) if hash.key?(from) end end hash end |
#rekey!(key_map = nil, &block) ⇒ Object
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 #=> { "name"=>"Gavin", "wife"=>:Lisa }
CREDIT: Trans, Gavin Kistner
77 78 79 |
# File 'lib/core/facets/hash/rekey.rb', line 77 def rekey!(key_map=nil, &block) replace(rekey(key_map, &block)) end |
#remove!(*rejected) ⇒ Object
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.
30 31 32 33 34 |
# File 'lib/core/facets/hash/except.rb', line 30 def remove!(*rejected) removed = {} rejected.each{ |k| removed[k] = delete(k) } removed end |
#replace_each ⇒ Object
Same as #update_each, but deletes the key element first.
CREDIT: Trans
7 8 9 10 11 12 13 |
# 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 |
#revalue(val_map = nil, &block) ⇒ Object
Generates a new hash where the values are the result of the passed in block. The block takes both the key and value of the current entry as arguments.
hash = { a: 1, b: 2 }
hash.revalue { |v| v + 1 } # => { a: 2, b: 3 }
Returns [Hash].
Credit: Sean Mackesey
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/core/facets/hash/revalue.rb', line 14 def revalue(val_map=nil, &block) raise ArgumentError, "argument or block, not both" if val_map && block if !(val_map or block) raise ArgumentError, "must provide Hash arguments or a block" #block = lambda{|v| v.to_s} end if block hash = dup.clear # to keep default_proc if block.arity.abs == 1 each_pair do |k, v| hash[k] = block[v] #hash[k] = block[v] || v end else each_pair do |k, v| hash[k] = block[k,v] #hash[k] = block[k,v] || v end end else hash = dup.clear # to keep default_proc each do |k,v| if val_map.key?(v) hash[k] = val_map[v] else hash[k] = v end end end hash end |
#revalue!(val_map = nil, &block) ⇒ Object
The in-place version of Hash#revalue.
hash = { a: 1, b: 2 }
hash.revalue! { |v| v + 1 }
hash # => { a: 2, b: 3 }
Returns [Hash].
Credit: Sean Mackesey
57 58 59 |
# File 'lib/core/facets/hash/revalue.rb', line 57 def revalue!(val_map=nil, &block) replace(revalue(val_map, &block)) end |
#reverse_merge(other) ⇒ Object
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( = {})
.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.
15 16 17 |
# File 'lib/core/facets/hash/reverse_merge.rb', line 15 def reverse_merge(other) other.merge(self) end |
#reverse_merge!(other) ⇒ Object Also known as: reverse_update
Inplace form of #reverse_merge.
21 22 23 |
# File 'lib/core/facets/hash/reverse_merge.rb', line 21 def reverse_merge!(other) replace(reverse_merge(other)) end |
#shelljoin ⇒ Object
110 111 112 |
# File 'lib/standard/facets/shellwords.rb', line 110 def shelljoin shellwords.shelljoin end |
#shellwords ⇒ Object
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'lib/standard/facets/shellwords.rb', line 90 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 << %[#{m}#{f}="#{e}"] end when true argv << %[#{m}#{f}] else argv << %[#{m}#{f}="#{v}"] end end argv end |
#slice(*keep_keys) ⇒ Object
Returns a new hash with only the given keys.
h = {:a=>1, :b=>2, :c=>3}
h.slice(:a, :c) #=> {:a=>1, :c=>3}
h.slice(:a, :d) #=> {:a=>1}
9 10 11 12 13 14 15 16 17 18 19 20 21 |
# File 'lib/core/facets/hash/slice.rb', line 9 def slice(*keep_keys) if block_given? each do |k, v| keep_keys << k if yield(k, v) end end hash = {} keep_keys.each do |key| hash[key] = fetch(key) if key?(key) end hash end |
#slice!(*keep_keys) ⇒ Object
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.
31 32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/core/facets/hash/slice.rb', line 31 def slice!(*keep_keys) if block_given? each do |k, v| keep_keys << k if yield(k, v) end end rejected = keys - keep_keys removed = {} rejected.each{ |k| removed[k] = delete(k) } removed end |
#stringify_keys(&select) ⇒ Object
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.
61 62 63 |
# File 'lib/core/facets/hash/symbolize_keys.rb', line 61 def stringify_keys(&select) dup.stringify_keys!(&select) end |
#stringify_keys!(&select) ⇒ Object
Destructively convert all keys to strings. This is the same as Hash#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.
76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/core/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, &block) ⇒ Object
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
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
# File 'lib/core/facets/hash/subset.rb', line 10 def subset(*keys, &block) h = {} if block raise ArgumentError, "subset arguments and block are exclusive parameters" unless keys.empty? each do |k, v| h[k] = v if block.call(k) end else each do |k, v| h[k] = v if keys.include?(k) end end return h end |
#swap!(key1, key2) ⇒ Object
Swap the values of a pair of keys in place.
{:a=>1,:b=>2}.swap!(:a,:b) #=> {:a=>2,:b=>1}
CREDIT: Gavin Sinclair
9 10 11 12 13 14 |
# 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(&select) ⇒ Object
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.
18 19 20 |
# File 'lib/core/facets/hash/symbolize_keys.rb', line 18 def symbolize_keys(&select) dup.symbolize_keys!(&select) end |
#symbolize_keys!(&select) ⇒ Object
Destructively convert all keys to symbols. This is the same as Hash#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.
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/core/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 ⇒ Object
Boolean conversion for not empty?
117 118 119 |
# File 'lib/core/facets/boolean.rb', line 117 def to_b ! self.empty? end |
#to_mod(&block) ⇒ Object
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 – TODO: Consider #to_obj? ++
20 21 22 23 24 25 26 27 28 29 30 |
# File 'lib/core/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_ostruct ⇒ Object
Turns a hash into a generic object using an OpenStruct.
o = {'a' => 1}.to_ostruct
o.a #=> 1
16 17 18 |
# File 'lib/standard/facets/ostruct/to_ostruct.rb', line 16 def to_ostruct OpenStruct.new(self) end |
#to_ostruct_recurse(exclude = {}) ⇒ Object
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. e.g.
h = { 'a' => { 'b' => 1 } }
o = h.to_ostruct_recurse( { h['a'] => h['a'] } )
o.a['b'] #=> 1
CREDIT: Alison Rowland, Jamie Macey, Mat Schaffer
48 49 50 51 52 53 54 55 56 |
# File 'lib/standard/facets/ostruct/to_ostruct.rb', line 48 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.merge!(h) end |
#to_proc(response = false) ⇒ Object
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
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
# File 'lib/core/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) ⇒ Object
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
12 13 14 |
# File 'lib/core/facets/hash/to_struct.rb', line 12 def to_struct(struct_name) Struct.new(struct_name,*keys).new(*values) end |
#traverse(&block) ⇒ Object
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: Hash#traverse is the same as ‘recursive.graph` and might be deprecated in the future (if it ever works!)
CREDIT: Trans
18 19 20 21 22 23 24 25 26 27 28 29 |
# File 'lib/core/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) ⇒ Object
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
42 43 44 |
# File 'lib/core/facets/hash/traverse.rb', line 42 def traverse!(&block) replace(traverse(&block)) end |
#update_each ⇒ Object
Iterates through each pair and updates 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
10 11 12 13 14 15 |
# 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 ⇒ Object
Iterate over hash updating just the keys.
h = {:a=>1, :b=>2}
h.update_keys{ |k| "#{k}!" }
h #=> { "a!"=>1, "b!"=>2 }
12 13 14 15 16 17 18 |
# File 'lib/core/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 ⇒ Object
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
11 12 13 14 15 16 17 |
# 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) ⇒ Object
Weave is a very unique hash operator. It 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
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/core/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) ⇒ Object
Operator for #reverse_merge.
CREDIT: Trans
7 8 9 |
# File 'lib/core/facets/hash/op_or.rb', line 7 def |(other) other.merge(self) end |