Skip to content

Commit

Permalink
Merge nil values or keep the original via an option
Browse files Browse the repository at this point in the history
For some people, it's unexpected that explicitly merging in a nil will
not overwrite an existing value.
`DeepMerge::deep_merge({:a => nil}, {:a => 1})`

Currently, we retain the 1 value.
My expectation is we'd get a nil value.

Since changing this is a change in behavior, and possibly not desirable,
I'm exposing an option to opt-in to this new behavior.

Note, this is related to danielsdeleo#20 and can be confusing to see the difference.
This commit handles merging a nil value into an existing destination via
an option.
PR danielsdeleo#20 handles NOT merging a value into an already nil destination.
  • Loading branch information
jrafanie committed Apr 25, 2017
1 parent 989b2df commit df851ce
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 2 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,15 @@ Push src elements to existing arrays, instead of overwriting them.
dest.deep_merge!(source, {:extend_existing_arrays => true})
Results: {"property" => ["1", "2", "3", "4"]}

**:merge_nil_values**

The purpose of this option is to allow nil hash values to be merged. The prior behavior was to discard nil hash values and remains the default if not specified.

source = {"item" => nil}
dest = {"item" => 'existing'}
dest.deep_merge!(source, {:merge_nil_values => true})
Results: {"item" => nil}

There are many tests for this library - and you can learn more about the features and usages of deep_merge! by just browsing the test examples.

Using deep_merge in Rails
Expand Down
4 changes: 3 additions & 1 deletion lib/deep_merge/core.rb
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,12 @@ def self.deep_merge!(source, dest, options = {})
extend_existing_arrays = options[:extend_existing_arrays] || false
# request that arrays keep duplicate elements
keep_array_duplicates = options[:keep_array_duplicates] || false
# request that nil values are merged or skipped (Skipped/false by default)
merge_nil_values = options[:merge_nil_values] || false

di = options[:debug_indent] || ''
# do nothing if source is nil
return dest if source.nil?
return dest if !merge_nil_values && source.nil?
# if dest doesn't exist, then simply copy source to it
if !(dest) && overwrite_unmergeable
dest = source; return dest
Expand Down
11 changes: 10 additions & 1 deletion test/test_deep_merge.rb
Original file line number Diff line number Diff line change
Expand Up @@ -630,7 +630,16 @@ def test_deep_merge
DeepMerge::deep_merge!(hash_src, hash_dst, {:keep_array_duplicates => true})
assert_equal({"item" => ["1", "2", "2", "3"]}, hash_dst)

# Don't merge nil values by default
hash_src = {"item" => nil}
hash_dst = {"item" => 'existing'}
DeepMerge::deep_merge!(hash_src, hash_dst)
assert_equal({"item" => 'existing'}, hash_dst)


# Merge nil values via an explicit: :merge_nil_values => true
hash_src = {"item" => nil}
hash_dst = {"item" => 'existing'}
DeepMerge::deep_merge!(hash_src, hash_dst, {:merge_nil_values => true})
assert_equal({"item" => nil}, hash_dst)
end # test_deep_merge
end

0 comments on commit df851ce

Please sign in to comment.