From e0e2c7e5f298c55981a173844112433ee92e85db Mon Sep 17 00:00:00 2001 From: Joe Rafaniello Date: Fri, 21 Apr 2017 16:22:57 -0400 Subject: [PATCH] Merge nil values or keep the original via an option 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 #20 and can be confusing to see the difference. This commit handles merging a nil value into an existing destination via an option. PR #20 handles NOT merging a value into an already nil destination. --- README.md | 9 +++++++++ lib/deep_merge/core.rb | 4 +++- test/test_deep_merge.rb | 11 ++++++++++- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6f0991c..a2081cd 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/lib/deep_merge/core.rb b/lib/deep_merge/core.rb index 6ec3a2f..cc43f60 100644 --- a/lib/deep_merge/core.rb +++ b/lib/deep_merge/core.rb @@ -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 diff --git a/test/test_deep_merge.rb b/test/test_deep_merge.rb index 84a8f00..2fffb12 100644 --- a/test/test_deep_merge.rb +++ b/test/test_deep_merge.rb @@ -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