Method: Hash#weave

Defined in:
lib/core/facets/hash/weave.rb

#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

Raises:

  • (ArgumentError)
[View source] [View on GitHub]

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