Module: Chef::Mixin::DeepMerge Private
Overview
This module is part of a private API. You should avoid using this module if possible, as it may be removed or be changed in the future.
Implements a deep merging algorithm for nested data structures.
This code was originally imported from deep_merge by Steve Midgley. deep_merge is available under the MIT license from trac.misuse.org/science/wiki/DeepMerge
Note that this is not considered a public interface. It is technically public and has been used and we cannot break the API, but continued external use is discouraged. We are unlikely to change the shape of the API and break anyone, but this code does not serve the purposes of cookbook authors and customers. It is intended only for the purposes of the internal use in the chef-client codebase. We do not accept pull requests to extend the functionality of this algorithm. Users who find this does nearly what they want, should copy and paste the algorithm and tune to their needs. We will not maintain any additional use cases.
“It is what it is, and if it isn’t what you want, you need to build that yourself”
Defined Under Namespace
Classes: InvalidParameter
Instance Method Summary collapse
- #deep_merge(source, dest) ⇒ Object private
-
#deep_merge!(source, dest) ⇒ Object
private
deep_merge! method permits merging of arbitrary child elements.
- #hash_only_merge(merge_onto, merge_with) ⇒ Object private
-
#hash_only_merge!(merge_onto, merge_with) ⇒ Object
private
Deep merge without Array merge.
- #merge(first, second) ⇒ Object private
- #safe_dup(thing) ⇒ Object private
Instance Method Details
#deep_merge(source, dest) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
151 152 153 |
# File 'lib/chef/mixin/deep_merge.rb', line 151 def deep_merge(source, dest) deep_merge!(safe_dup(source), safe_dup(dest)) end |
#deep_merge!(source, dest) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
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)
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/chef/mixin/deep_merge.rb', line 77 def deep_merge!(source, dest) case source when Hash if dest.is_a?(Hash) source.each do |src_key, src_value| if dest.key?(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.is_a?(Array) 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
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
106 107 108 |
# File 'lib/chef/mixin/deep_merge.rb', line 106 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
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
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.
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
# File 'lib/chef/mixin/deep_merge.rb', line 124 def hash_only_merge!(merge_onto, merge_with) # If there are two Hashes, recursively merge. if merge_onto.is_a?(Hash) && merge_with.is_a?(Hash) merge_with.each do |key, merge_with_value| value = if merge_onto.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 # In all other cases, replace merge_onto with merge_with else merge_with end end |
#merge(first, second) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
49 50 51 52 53 54 |
# File 'lib/chef/mixin/deep_merge.rb', line 49 def merge(first, second) first = Mash.new(first) unless first.is_a?(Mash) second = Mash.new(second) unless second.is_a?(Mash) DeepMerge.deep_merge(second, first) end |
#safe_dup(thing) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
111 112 113 114 115 |
# File 'lib/chef/mixin/deep_merge.rb', line 111 def safe_dup(thing) thing.dup rescue TypeError thing end |