Module: Chef::Mixin::DeepMerge
Overview
Chef::Mixin::DeepMerge
Implements a deep merging algorithm for nested data structures.
Notice:
This code was originally imported from deep_merge by Steve Midgley.
deep_merge is available under the MIT license from
http://trac.misuse.org/science/wiki/DeepMerge
Defined Under Namespace
Classes: InvalidParameter
Instance Method Summary collapse
- #deep_merge(source, dest) ⇒ Object
-
#deep_merge!(source, dest) ⇒ Object
Deep Merge core documentation.
-
#hash_only_merge(merge_onto, merge_with) ⇒ Object
deep_merge!.
-
#hash_only_merge!(merge_onto, merge_with) ⇒ Object
Deep merge without Array merge.
- #merge(first, second) ⇒ Object
- #safe_dup(thing) ⇒ Object
Instance Method Details
#deep_merge(source, dest) ⇒ Object
134 135 136 |
# File 'lib/chef/mixin/deep_merge.rb', line 134 def deep_merge(source, dest) deep_merge!(safe_dup(source), safe_dup(dest)) end |
#deep_merge!(source, dest) ⇒ Object
Deep Merge core documentation. deep_merge! method permits merging of arbitrary child elements. The two top level elements must be hashes. These hashes can contain unlimited (to stack limit) levels of child elements. These child elements to not have to be of the same types. Where child elements are of the same type, deep_merge will attempt to merge them together. Where child elements are not of the same type, deep_merge will skip or optionally overwrite the destination element with the contents of the source element at that level. So if you have two hashes like this:
source = {:x => [1,2,3], :y => 2}
dest = {:x => [4,5,'6'], :y => [7,8,9]}
dest.deep_merge!(source)
Results: {:x => [1,2,3,4,5,'6'], :y => 2}
By default, “deep_merge!” will overwrite any unmergeables and merge everything else. To avoid this, use “deep_merge” (no bang/exclamation mark)
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/chef/mixin/deep_merge.rb', line 55 def deep_merge!(source, dest) # if dest doesn't exist, then simply copy source to it if dest.nil? dest = source; return dest end case source when nil dest when Hash if dest.kind_of?(Hash) source.each do |src_key, src_value| if dest[src_key] dest[src_key] = deep_merge!(src_value, dest[src_key]) else # dest[src_key] doesn't exist so we take whatever source has dest[src_key] = src_value end end else # dest isn't a hash, so we overwrite it completely dest = source end when Array if dest.kind_of?(Array) dest = dest | source else dest = source end when String dest = source else # src_hash is not an array or hash, so we'll have to overwrite dest dest = source end dest end |
#hash_only_merge(merge_onto, merge_with) ⇒ Object
deep_merge!
90 91 92 |
# File 'lib/chef/mixin/deep_merge.rb', line 90 def hash_only_merge(merge_onto, merge_with) hash_only_merge!(safe_dup(merge_onto), safe_dup(merge_with)) end |
#hash_only_merge!(merge_onto, merge_with) ⇒ Object
Deep merge without Array merge. ‘merge_onto` is the object that will “lose” in case of conflict. `merge_with` is the object whose values will replace `merge_onto`s values when there is a conflict.
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
# File 'lib/chef/mixin/deep_merge.rb', line 104 def hash_only_merge!(merge_onto, merge_with) # If there are two Hashes, recursively merge. if merge_onto.kind_of?(Hash) && merge_with.kind_of?(Hash) merge_with.each do |key, merge_with_value| value = if merge_onto.has_key?(key) hash_only_merge(merge_onto[key], merge_with_value) else merge_with_value end if merge_onto.respond_to?(:public_method_that_only_deep_merge_should_use) # we can't call ImmutableMash#[]= because its immutable, but we need to mutate it to build it in-place merge_onto.public_method_that_only_deep_merge_should_use(key, value) else merge_onto[key] = value end end merge_onto # If merge_with is nil, don't replace merge_onto elsif merge_with.nil? merge_onto # In all other cases, replace merge_onto with merge_with else merge_with end end |
#merge(first, second) ⇒ Object
32 33 34 35 36 37 |
# File 'lib/chef/mixin/deep_merge.rb', line 32 def merge(first, second) first = Mash.new(first) unless first.kind_of?(Mash) second = Mash.new(second) unless second.kind_of?(Mash) DeepMerge.deep_merge(second, first) end |
#safe_dup(thing) ⇒ Object
94 95 96 97 98 |
# File 'lib/chef/mixin/deep_merge.rb', line 94 def safe_dup(thing) thing.dup rescue TypeError thing end |