deep_merge2 1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f9c735594bdafaa3934a7c07ffd9bb113b5d1c22
4
+ data.tar.gz: 1080c8b06d62ffac4dff4326800ded67cfc745af
5
+ SHA512:
6
+ metadata.gz: 70ff44480f9bd22804b3c5c609fc32779a9200846f658a80ef97dc294ffc38150a44b12b3e487a34af5f1b816cf33803f69f731f0804e3854ee1a1735be73fa5
7
+ data.tar.gz: c5e5866ab2357b5f8349f4993b56bfedfeffe8371b86264c2f3b3c42ef666bdbda8f714e36c5f9bf2c0cb13dd93753601efc9ba682e98142210847a506a29f82
@@ -0,0 +1,45 @@
1
+ 2014-01-21 Dan DeLeo <dan@kallistec.com>
2
+ * Update knockout behavior to better handle nil (b7de40b5)
3
+
4
+ 2011-08-15 Dan DeLeo <dan@kallistec.com>
5
+ * Document how to use w/ Rails 3 via Bundler
6
+
7
+ 2011-07-28 Dan DeLeo <dan@kallistec.com>
8
+ * Use a plain ol' gemspec and Rakefile for gem creation
9
+
10
+ * Ship version 1.0.0
11
+
12
+ 2011-05-23 Joe Van Dyk <joe@fixieconsulting.com>
13
+
14
+ * Added Changelog
15
+
16
+ 2011-05-18 Joe Van Dyk <joe@fixieconsulting.com>
17
+
18
+ * Merging empty strings should work if String#blank? is defined.
19
+
20
+ * Use unix line endings
21
+
22
+ * Removing extra whitespace
23
+
24
+ 2010-01-11 Dan DeLeo <dan@kallistec.com>
25
+
26
+ * fix boolean merging according to mdkent's patch explicitly test
27
+ for nils w/ #nil? instead of negating. Thanks mdkent!
28
+
29
+ 2009-12-25 Dan DeLeo <dan@kallistec.com>
30
+
31
+ * miscellaneous cleanup
32
+
33
+ * make rails/active_support compat optional
34
+
35
+ * add jeweler rake task for gemability
36
+
37
+ 2009-12-24 Dan DeLeo <dan@kallistec.com>
38
+
39
+ * VERSION: Version bump to 0.0.1
40
+
41
+ * VERSION: Version bump to 0.0.0
42
+
43
+ 2009-11-06 Jonathan Weiss <jw@innerewut.de>
44
+
45
+ * import
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2008-2104 Steve Midgley, Daniel DeLeo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,135 @@
1
+ DeepMerge Overview
2
+ ==================
3
+
4
+ Deep Merge is a simple set of utility functions for Hash. It permits you to merge elements inside a hash together recursively. The manner by which it does this is somewhat arbitrary (since there is no defining standard for this) but it should end up being pretty intuitive and do what you expect.
5
+
6
+ You can learn a lot more about this by reading the test file. It's pretty well documented and has many examples of various merges from very simple to pretty complex.
7
+
8
+ The primary need that caused me to write this library is the merging of elements coming from HTTP parameters and related stored parameters in session. This lets a user build up a set of parameters over time, modifying individual items.
9
+
10
+ Deep Merge Core Documentation
11
+ =============================
12
+
13
+ `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:
14
+
15
+ source = {:x => [1,2,3], :y => 2}
16
+ dest = {:x => [4,5,'6'], :y => [7,8,9]}
17
+ dest.deep_merge!(source)
18
+ Results: {:x => [1,2,3,4,5,'6'], :y => 2}
19
+
20
+ By default, `deep_merge!` will overwrite any unmergeables and merge everything else. To avoid this, use `deep_merge` (no bang/exclamation mark)
21
+
22
+ Options
23
+ -------
24
+
25
+ Options are specified in the last parameter passed, which should be in hash format:
26
+
27
+ hash.deep_merge!({:x => [1,2]}, {:knockout_prefix => '--'})
28
+ :preserve_unmergeables DEFAULT: false
29
+ Set to true to skip any unmergeable elements from source
30
+ :knockout_prefix DEFAULT: nil
31
+ Set to string value to signify prefix which deletes elements from existing element
32
+ :overwrite_arrays DEFAULT: false
33
+ Set to true if you want to avoid merging arrays
34
+ :sort_merged_arrays DEFAULT: false
35
+ Set to true to sort all arrays that are merged together
36
+ :unpack_arrays DEFAULT: nil
37
+ Set to string value to run "Array::join" then "String::split" against all arrays
38
+ :merge_hash_arrays DEFAULT: false
39
+ Set to true to merge hashes within arrays
40
+ :extend_existing_arrays DEFAULT: false
41
+ Set to true to extend existing arrays, instead of overwriting them
42
+ :merge_debug DEFAULT: false
43
+ Set to true to get console output of merge process for debugging
44
+
45
+ Selected Options Details
46
+ ------------------------
47
+
48
+ **:knockout_prefix**
49
+
50
+ The purpose of this is to provide a way to remove elements from existing Hash by specifying them in a special way in incoming hash
51
+
52
+ source = {:x => ['--1', '2']}
53
+ dest = {:x => ['1', '3']}
54
+ dest.ko_deep_merge!(source)
55
+ Results: {:x => ['2','3']}
56
+
57
+ Additionally, if the knockout_prefix is passed alone as a string, it will cause the entire element to be removed:
58
+
59
+ source = {:x => '--'}
60
+ dest = {:x => [1,2,3]}
61
+ dest.ko_deep_merge!(source)
62
+ Results: {:x => ""}
63
+
64
+ **:overwrite_arrays**
65
+
66
+ The purpose of this is to provide a way to replace Arrays instead of having them merge together.
67
+
68
+ source = {:x => ['1', '2']}
69
+ dest = {:x => ['3', '4']}
70
+ dest.deep_merge!(source, {:overwrite_arrays => true})
71
+ Results: {:x => ['1', '2']}
72
+
73
+ **:unpack_arrays**
74
+
75
+ The purpose of this is to permit compound elements to be passed in as strings and to be converted into discrete array elements
76
+
77
+ irsource = {:x => ['1,2,3', '4']}
78
+ dest = {:x => ['5','6','7,8']}
79
+ dest.deep_merge!(source, {:unpack_arrays => ','})
80
+ Results: {:x => ['1','2','3','4','5','6','7','8'}
81
+
82
+ Why: If receiving data from an HTML form, this makes it easy for a checkbox to pass multiple values from within a single HTML element
83
+
84
+ **:merge_hash_arrays**
85
+
86
+ merge hashes within arrays
87
+
88
+ source = {:x => [{:y => 1}]}
89
+ dest = {:x => [{:z => 2}]}
90
+ dest.deep_merge!(source, {:merge_hash_arrays => true})
91
+ Results: {:x => [{:y => 1, :z => 2}]}
92
+
93
+ **:extend_existing_arrays**
94
+
95
+ Push src elements to existing arrays, instead of overwriting them.
96
+
97
+ source = { "property" => "4" }
98
+ dest = { "property" => ["1", "2", "3"] }
99
+ dest.deep_merge!(source, {:extend_existing_arrays => true})
100
+ Results: {"property" => ["1", "2", "3", "4"]}
101
+
102
+ 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.
103
+
104
+ Using deep_merge in Rails
105
+ =========================
106
+
107
+ To avoid conflict with ActiveSupport, load deep_merge via:
108
+
109
+ require 'deep_merge/rails_compat'
110
+
111
+ In a Gemfile:
112
+
113
+ gem "deep_merge", :require => 'deep_merge/rails_compat'
114
+
115
+ The deep_merge methods will then be defined as
116
+
117
+ Hash#deeper_merge
118
+ Hash#deeper_merge!
119
+ Hash#ko_deeper_merge!
120
+
121
+ Simple Example Code
122
+ ===================
123
+
124
+ require 'deep_merge'
125
+ x = {:x => [3,4,5]}
126
+ y = {:x => [1,2,3]}
127
+ y.deep_merge!(x)
128
+ # results: y = {:x => [1,2,3,4,5]}
129
+
130
+ Availablility
131
+ =============
132
+
133
+ `deep_merge` was written by Steve Midgley, and is now maintained by Daniel DeLeo. The official home of `deep_merge` on the internet is now https://github.com/danielsdeleo/deep_merge
134
+
135
+ Copyright (c) 2008 Steve Midgley, released under the MIT license
@@ -0,0 +1,19 @@
1
+ require 'rake/testtask'
2
+
3
+ Rake::TestTask.new do |t|
4
+ t.libs << FileList['lib/**.rb']
5
+ t.test_files = FileList['test/test*.rb']
6
+ end
7
+
8
+ task :default => :test
9
+
10
+ begin
11
+ require 'rubygems'
12
+ require 'rubygems/package_task'
13
+
14
+ gemspec = eval(IO.read('deep_merge.gemspec'))
15
+ Gem::PackageTask.new(gemspec).define
16
+ rescue LoadError
17
+ #okay, then
18
+ end
19
+
@@ -0,0 +1,2 @@
1
+ require 'deep_merge/core'
2
+ require 'deep_merge/deep_merge_hash'
@@ -0,0 +1,228 @@
1
+ module DeepMerge
2
+
3
+ class InvalidParameter < StandardError; end
4
+
5
+ DEFAULT_FIELD_KNOCKOUT_PREFIX = '--'
6
+
7
+ # Deep Merge core documentation.
8
+ # deep_merge! method permits merging of arbitrary child elements. The two top level
9
+ # elements must be hashes. These hashes can contain unlimited (to stack limit) levels
10
+ # of child elements. These child elements to not have to be of the same types.
11
+ # Where child elements are of the same type, deep_merge will attempt to merge them together.
12
+ # Where child elements are not of the same type, deep_merge will skip or optionally overwrite
13
+ # the destination element with the contents of the source element at that level.
14
+ # So if you have two hashes like this:
15
+ # source = {:x => [1,2,3], :y => 2}
16
+ # dest = {:x => [4,5,'6'], :y => [7,8,9]}
17
+ # dest.deep_merge!(source)
18
+ # Results: {:x => [1,2,3,4,5,'6'], :y => 2}
19
+ # By default, "deep_merge!" will overwrite any unmergeables and merge everything else.
20
+ # To avoid this, use "deep_merge" (no bang/exclamation mark)
21
+ #
22
+ # Options:
23
+ # Options are specified in the last parameter passed, which should be in hash format:
24
+ # hash.deep_merge!({:x => [1,2]}, {:knockout_prefix => '--'})
25
+ # :preserve_unmergeables DEFAULT: false
26
+ # Set to true to skip any unmergeable elements from source
27
+ # :knockout_prefix DEFAULT: nil
28
+ # Set to string value to signify prefix which deletes elements from existing element
29
+ # :overwrite_arrays DEFAULT: false
30
+ # Set to true if you want to avoid merging arrays
31
+ # :sort_merged_arrays DEFAULT: false
32
+ # Set to true to sort all arrays that are merged together
33
+ # :unpack_arrays DEFAULT: nil
34
+ # Set to string value to run "Array::join" then "String::split" against all arrays
35
+ # :merge_hash_arrays DEFAULT: false
36
+ # Set to true to merge hashes within arrays
37
+ # :merge_debug DEFAULT: false
38
+ # Set to true to get console output of merge process for debugging
39
+ #
40
+ # Selected Options Details:
41
+ # :knockout_prefix => The purpose of this is to provide a way to remove elements
42
+ # from existing Hash by specifying them in a special way in incoming hash
43
+ # source = {:x => ['--1', '2']}
44
+ # dest = {:x => ['1', '3']}
45
+ # dest.ko_deep_merge!(source)
46
+ # Results: {:x => ['2','3']}
47
+ # Additionally, if the knockout_prefix is passed alone as a string, it will cause
48
+ # the entire element to be removed:
49
+ # source = {:x => '--'}
50
+ # dest = {:x => [1,2,3]}
51
+ # dest.ko_deep_merge!(source)
52
+ # Results: {:x => ""}
53
+ # :unpack_arrays => The purpose of this is to permit compound elements to be passed
54
+ # in as strings and to be converted into discrete array elements
55
+ # irsource = {:x => ['1,2,3', '4']}
56
+ # dest = {:x => ['5','6','7,8']}
57
+ # dest.deep_merge!(source, {:unpack_arrays => ','})
58
+ # Results: {:x => ['1','2','3','4','5','6','7','8'}
59
+ # Why: If receiving data from an HTML form, this makes it easy for a checkbox
60
+ # to pass multiple values from within a single HTML element
61
+ #
62
+ # :merge_hash_arrays => merge hashes within arrays
63
+ # source = {:x => [{:y => 1}]}
64
+ # dest = {:x => [{:z => 2}]}
65
+ # dest.deep_merge!(source, {:merge_hash_arrays => true})
66
+ # Results: {:x => [{:y => 1, :z => 2}]}
67
+ #
68
+ # There are many tests for this library - and you can learn more about the features
69
+ # and usages of deep_merge! by just browsing the test examples
70
+ def self.deep_merge!(source, dest, options = {})
71
+ # turn on this line for stdout debugging text
72
+ merge_debug = options[:merge_debug] || false
73
+ overwrite_unmergeable = !options[:preserve_unmergeables]
74
+ knockout_prefix = options[:knockout_prefix] || nil
75
+ raise InvalidParameter, "knockout_prefix cannot be an empty string in deep_merge!" if knockout_prefix == ""
76
+ raise InvalidParameter, "overwrite_unmergeable must be true if knockout_prefix is specified in deep_merge!" if knockout_prefix && !overwrite_unmergeable
77
+ # if present: we will split and join arrays on this char before merging
78
+ array_split_char = options[:unpack_arrays] || false
79
+ # request that we avoid merging arrays
80
+ overwrite_arrays = options[:overwrite_arrays] || false
81
+ # request that we sort together any arrays when they are merged
82
+ sort_merged_arrays = options[:sort_merged_arrays] || false
83
+ # request that arrays of hashes are merged together
84
+ merge_hash_arrays = options[:merge_hash_arrays] || false
85
+ # request to extend existing arrays, instead of overwriting them
86
+ extend_existing_arrays = options[:extend_existing_arrays] || false
87
+
88
+ di = options[:debug_indent] || ''
89
+ # do nothing if source is nil
90
+ return dest if source.nil?
91
+ # if dest doesn't exist, then simply copy source to it
92
+ if !(dest) && overwrite_unmergeable
93
+ dest = source; return dest
94
+ end
95
+
96
+ puts "#{di}Source class: #{source.class.inspect} :: Dest class: #{dest.class.inspect}" if merge_debug
97
+ if source.kind_of?(Hash)
98
+ puts "#{di}Hashes: #{source.inspect} :: #{dest.inspect}" if merge_debug
99
+ source.each do |src_key, src_value|
100
+ if dest.kind_of?(Hash)
101
+ puts "#{di} looping: #{src_key.inspect} => #{src_value.inspect} :: #{dest.inspect}" if merge_debug
102
+ if dest[src_key]
103
+ puts "#{di} ==>merging: #{src_key.inspect} => #{src_value.inspect} :: #{dest[src_key].inspect}" if merge_debug
104
+ dest[src_key] = deep_merge!(src_value, dest[src_key], options.merge(:debug_indent => di + ' '))
105
+ else # dest[src_key] doesn't exist so we want to create and overwrite it (but we do this via deep_merge!)
106
+ puts "#{di} ==>merging over: #{src_key.inspect} => #{src_value.inspect}" if merge_debug
107
+ # note: we rescue here b/c some classes respond to "dup" but don't implement it (Numeric, TrueClass, FalseClass, NilClass among maybe others)
108
+ begin
109
+ src_dup = src_value.dup # we dup src_value if possible because we're going to merge into it (since dest is empty)
110
+ rescue TypeError
111
+ src_dup = src_value
112
+ end
113
+ dest[src_key] = deep_merge!(src_value, src_dup, options.merge(:debug_indent => di + ' '))
114
+ end
115
+ elsif dest.kind_of?(Array) && extend_existing_arrays
116
+ dest.push(source)
117
+ else # dest isn't a hash, so we overwrite it completely (if permitted)
118
+ if overwrite_unmergeable
119
+ puts "#{di} overwriting dest: #{src_key.inspect} => #{src_value.inspect} -over-> #{dest.inspect}" if merge_debug
120
+ dest = overwrite_unmergeables(source, dest, options)
121
+ end
122
+ end
123
+ end
124
+ elsif source.kind_of?(Array)
125
+ puts "#{di}Arrays: #{source.inspect} :: #{dest.inspect}" if merge_debug
126
+ if overwrite_arrays
127
+ puts "#{di} overwrite arrays" if merge_debug
128
+ dest = source
129
+ else
130
+ # if we are instructed, join/split any source arrays before processing
131
+ if array_split_char
132
+ puts "#{di} split/join on source: #{source.inspect}" if merge_debug
133
+ source = source.join(array_split_char).split(array_split_char)
134
+ if dest.kind_of?(Array)
135
+ dest = dest.join(array_split_char).split(array_split_char)
136
+ end
137
+ end
138
+ # if there's a naked knockout_prefix in source, that means we are to truncate dest
139
+ if knockout_prefix && source.index(knockout_prefix)
140
+ dest = clear_or_nil(dest); source.delete(knockout_prefix)
141
+ end
142
+ if dest.kind_of?(Array)
143
+ if knockout_prefix
144
+ print "#{di} knocking out: " if merge_debug
145
+ # remove knockout prefix items from both source and dest
146
+ source.delete_if do |ko_item|
147
+ retval = false
148
+ item = ko_item.respond_to?(:gsub) ? ko_item.gsub(%r{^#{knockout_prefix}}, "") : ko_item
149
+ if item != ko_item
150
+ print "#{ko_item} - " if merge_debug
151
+ dest.delete(item)
152
+ dest.delete(ko_item)
153
+ retval = true
154
+ end
155
+ retval
156
+ end
157
+ puts if merge_debug
158
+ end
159
+ puts "#{di} merging arrays: #{source.inspect} :: #{dest.inspect}" if merge_debug
160
+ source_all_hashes = source.all? { |i| i.kind_of?(Hash) }
161
+ dest_all_hashes = dest.all? { |i| i.kind_of?(Hash) }
162
+ if merge_hash_arrays && source_all_hashes && dest_all_hashes
163
+ # merge hashes in lists
164
+ list = []
165
+ dest.each_index do |i|
166
+ list[i] = deep_merge!(source[i] || {}, dest[i],
167
+ options.merge(:debug_indent => di + ' '))
168
+ end
169
+ list += source[dest.count..-1] if source.count > dest.count
170
+ dest = list
171
+ else
172
+ dest = dest | source
173
+ end
174
+ dest.sort! if sort_merged_arrays
175
+ elsif overwrite_unmergeable
176
+ puts "#{di} overwriting dest: #{source.inspect} -over-> #{dest.inspect}" if merge_debug
177
+ dest = overwrite_unmergeables(source, dest, options)
178
+ end
179
+ end
180
+ else # src_hash is not an array or hash, so we'll have to overwrite dest
181
+ if dest.kind_of?(Array) && extend_existing_arrays
182
+ dest.push(source)
183
+ else
184
+ puts "#{di}Others: #{source.inspect} :: #{dest.inspect}" if merge_debug
185
+ dest = overwrite_unmergeables(source, dest, options)
186
+ end
187
+ end
188
+ puts "#{di}Returning #{dest.inspect}" if merge_debug
189
+ dest
190
+ end # deep_merge!
191
+
192
+ # allows deep_merge! to uniformly handle overwriting of unmergeable entities
193
+ def self.overwrite_unmergeables(source, dest, options)
194
+ merge_debug = options[:merge_debug] || false
195
+ overwrite_unmergeable = !options[:preserve_unmergeables]
196
+ knockout_prefix = options[:knockout_prefix] || false
197
+ di = options[:debug_indent] || ''
198
+ if knockout_prefix && overwrite_unmergeable
199
+ if source.kind_of?(String) # remove knockout string from source before overwriting dest
200
+ src_tmp = source.gsub(%r{^#{knockout_prefix}},"")
201
+ elsif source.kind_of?(Array) # remove all knockout elements before overwriting dest
202
+ src_tmp = source.delete_if {|ko_item| ko_item.kind_of?(String) && ko_item.match(%r{^#{knockout_prefix}}) }
203
+ else
204
+ src_tmp = source
205
+ end
206
+ if src_tmp == source # if we didn't find a knockout_prefix then we just overwrite dest
207
+ puts "#{di}#{src_tmp.inspect} -over-> #{dest.inspect}" if merge_debug
208
+ dest = src_tmp
209
+ else # if we do find a knockout_prefix, then we just delete dest
210
+ puts "#{di}\"\" -over-> #{dest.inspect}" if merge_debug
211
+ dest = ""
212
+ end
213
+ elsif overwrite_unmergeable
214
+ dest = source
215
+ end
216
+ dest
217
+ end
218
+
219
+ def self.clear_or_nil(obj)
220
+ if obj.respond_to?(:clear)
221
+ obj.clear
222
+ else
223
+ obj = nil
224
+ end
225
+ obj
226
+ end
227
+
228
+ end # module DeepMerge
@@ -0,0 +1,28 @@
1
+ require 'deep_merge/core'
2
+
3
+ module DeepMerge
4
+ module DeepMergeHash
5
+ # ko_hash_merge! will merge and knockout elements prefixed with DEFAULT_FIELD_KNOCKOUT_PREFIX
6
+ def ko_deep_merge!(source, options = {})
7
+ default_opts = {:knockout_prefix => "--", :preserve_unmergeables => false}
8
+ DeepMerge::deep_merge!(source, self, default_opts.merge(options))
9
+ end
10
+
11
+ # deep_merge! will merge and overwrite any unmergeables in destination hash
12
+ def deep_merge!(source, options = {})
13
+ default_opts = {:preserve_unmergeables => false}
14
+ DeepMerge::deep_merge!(source, self, default_opts.merge(options))
15
+ end
16
+
17
+ # deep_merge will merge and skip any unmergeables in destination hash
18
+ def deep_merge(source, options = {})
19
+ default_opts = {:preserve_unmergeables => true}
20
+ DeepMerge::deep_merge!(source, self, default_opts.merge(options))
21
+ end
22
+
23
+ end # DeepMergeHashExt
24
+ end
25
+
26
+ class Hash
27
+ include DeepMerge::DeepMergeHash
28
+ end
@@ -0,0 +1,27 @@
1
+ require 'deep_merge/core'
2
+
3
+ module DeepMerge
4
+ module RailsCompat
5
+ # ko_hash_merge! will merge and knockout elements prefixed with DEFAULT_FIELD_KNOCKOUT_PREFIX
6
+ def ko_deeper_merge!(source, options = {})
7
+ default_opts = {:knockout_prefix => "--", :preserve_unmergeables => false}
8
+ DeepMerge::deep_merge!(source, self, default_opts.merge(options))
9
+ end
10
+
11
+ # deep_merge! will merge and overwrite any unmergeables in destination hash
12
+ def deeper_merge!(source, options = {})
13
+ default_opts = {:preserve_unmergeables => false}
14
+ DeepMerge::deep_merge!(source, self, default_opts.merge(options))
15
+ end
16
+
17
+ # deep_merge will merge and skip any unmergeables in destination hash
18
+ def deeper_merge(source, options = {})
19
+ default_opts = {:preserve_unmergeables => true}
20
+ DeepMerge::deep_merge!(source, self, default_opts.merge(options))
21
+ end
22
+ end
23
+ end
24
+
25
+ class Hash
26
+ include ::DeepMerge::RailsCompat
27
+ end
@@ -0,0 +1,626 @@
1
+ require 'test/unit'
2
+
3
+ $:.unshift(File.dirname(__FILE__) + '/../lib/')
4
+ require 'deep_merge'
5
+
6
+ # Assume strings have a blank? method
7
+ # as they do when ActiveSupport is included.
8
+ module StringBlank
9
+ def blank?
10
+ size == 0
11
+ end
12
+ end
13
+
14
+ class TestDeepMerge < Test::Unit::TestCase
15
+
16
+ def setup
17
+ end
18
+
19
+ # show that Hash object has deep merge capabilities in form of three methods:
20
+ # ko_deep_merge! # uses '--' knockout and overwrites unmergeable
21
+ # deep_merge! # overwrites unmergeable
22
+ # deep_merge # skips unmergeable
23
+ def test_hash_deep_merge
24
+ x = {}
25
+ assert x.respond_to?('deep_merge!'.to_sym)
26
+ hash_src = {'id' => [3,4,5]}
27
+ hash_dest = {'id' => [1,2,3]}
28
+ assert hash_dest.ko_deep_merge!(hash_src)
29
+ assert_equal({'id' => [1,2,3,4,5]}, hash_dest)
30
+
31
+ hash_src = {'id' => [3,4,5]}
32
+ hash_dest = {'id' => [1,2,3]}
33
+ assert hash_dest.deep_merge!(hash_src)
34
+ assert_equal({'id' => [1,2,3,4,5]}, hash_dest)
35
+
36
+ hash_src = {'id' => 'xxx'}
37
+ hash_dest = {'id' => [1,2,3]}
38
+ assert hash_dest.deep_merge(hash_src)
39
+ assert_equal({'id' => [1,2,3]}, hash_dest)
40
+ end
41
+
42
+ FIELD_KNOCKOUT_PREFIX = DeepMerge::DEFAULT_FIELD_KNOCKOUT_PREFIX
43
+
44
+ # tests DeepMerge::deep_merge! function
45
+ def test_deep_merge
46
+ # merge tests (moving from basic to more complex)
47
+
48
+ # test merging an hash w/array into blank hash
49
+ hash_src = {'id' => '2'}
50
+ hash_dst = {}
51
+ DeepMerge::deep_merge!(hash_src.dup, hash_dst, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ","})
52
+ assert_equal hash_src, hash_dst
53
+
54
+ # test merging an hash w/array into blank hash
55
+ hash_src = {'region' => {'id' => ['227', '2']}}
56
+ hash_dst = {}
57
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ","})
58
+ assert_equal hash_src, hash_dst
59
+
60
+ # merge from empty hash
61
+ hash_src = {}
62
+ hash_dst = {"property" => ["2","4"]}
63
+ DeepMerge::deep_merge!(hash_src, hash_dst)
64
+ assert_equal({"property" => ["2","4"]}, hash_dst)
65
+
66
+ # merge to empty hash
67
+ hash_src = {"property" => ["2","4"]}
68
+ hash_dst = {}
69
+ DeepMerge::deep_merge!(hash_src, hash_dst)
70
+ assert_equal({"property" => ["2","4"]}, hash_dst)
71
+
72
+ # simple string overwrite
73
+ hash_src = {"name" => "value"}
74
+ hash_dst = {"name" => "value1"}
75
+ DeepMerge::deep_merge!(hash_src, hash_dst)
76
+ assert_equal({"name" => "value"}, hash_dst)
77
+
78
+ # simple string overwrite of empty hash
79
+ hash_src = {"name" => "value"}
80
+ hash_dst = {}
81
+ DeepMerge::deep_merge!(hash_src, hash_dst)
82
+ assert_equal(hash_src, hash_dst)
83
+
84
+ # hashes holding array
85
+ hash_src = {"property" => ["1","3"]}
86
+ hash_dst = {"property" => ["2","4"]}
87
+ DeepMerge::deep_merge!(hash_src, hash_dst)
88
+ assert_equal(["2","4","1","3"], hash_dst['property'])
89
+
90
+ # hashes holding array (overwrite)
91
+ hash_src = {"property" => ["1","3"]}
92
+ hash_dst = {"property" => ["2","4"]}
93
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:overwrite_arrays => true})
94
+ assert_equal(["1","3"], hash_dst['property'])
95
+
96
+ # hashes holding array (sorted)
97
+ hash_src = {"property" => ["1","3"]}
98
+ hash_dst = {"property" => ["2","4"]}
99
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:sort_merged_arrays => true})
100
+ assert_equal(["1","2","3","4"].sort, hash_dst['property'])
101
+
102
+ # hashes holding hashes holding arrays (array with duplicate elements is merged with dest then src
103
+ hash_src = {"property" => {"bedroom_count" => ["1", "2"], "bathroom_count" => ["1", "4+"]}}
104
+ hash_dst = {"property" => {"bedroom_count" => ["3", "2"], "bathroom_count" => ["2"]}}
105
+ DeepMerge::deep_merge!(hash_src, hash_dst)
106
+ assert_equal({"property" => {"bedroom_count" => ["3","2","1"], "bathroom_count" => ["2", "1", "4+"]}}, hash_dst)
107
+
108
+ # hash holding hash holding array v string (string is overwritten by array)
109
+ hash_src = {"property" => {"bedroom_count" => ["1", "2"], "bathroom_count" => ["1", "4+"]}}
110
+ hash_dst = {"property" => {"bedroom_count" => "3", "bathroom_count" => ["2"]}}
111
+ DeepMerge::deep_merge!(hash_src, hash_dst)
112
+ assert_equal({"property" => {"bedroom_count" => ["1", "2"], "bathroom_count" => ["2","1","4+"]}}, hash_dst)
113
+
114
+ # hash holding hash holding array v string (string is NOT overwritten by array)
115
+ hash_src = {"property" => {"bedroom_count" => ["1", "2"], "bathroom_count" => ["1", "4+"]}}
116
+ hash_dst = {"property" => {"bedroom_count" => "3", "bathroom_count" => ["2"]}}
117
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:preserve_unmergeables => true})
118
+ assert_equal({"property" => {"bedroom_count" => "3", "bathroom_count" => ["2","1","4+"]}}, hash_dst)
119
+
120
+ # hash holding hash holding string v array (array is overwritten by string)
121
+ hash_src = {"property" => {"bedroom_count" => "3", "bathroom_count" => ["1", "4+"]}}
122
+ hash_dst = {"property" => {"bedroom_count" => ["1", "2"], "bathroom_count" => ["2"]}}
123
+ DeepMerge::deep_merge!(hash_src, hash_dst)
124
+ assert_equal({"property" => {"bedroom_count" => "3", "bathroom_count" => ["2","1","4+"]}}, hash_dst)
125
+
126
+ # hash holding hash holding string v array (array does NOT overwrite string)
127
+ hash_src = {"property" => {"bedroom_count" => "3", "bathroom_count" => ["1", "4+"]}}
128
+ hash_dst = {"property" => {"bedroom_count" => ["1", "2"], "bathroom_count" => ["2"]}}
129
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:preserve_unmergeables => true})
130
+ assert_equal({"property" => {"bedroom_count" => ["1", "2"], "bathroom_count" => ["2","1","4+"]}}, hash_dst)
131
+
132
+ # hash holding hash holding hash v array (array is overwritten by hash)
133
+ hash_src = {"property" => {"bedroom_count" => {"king_bed" => 3, "queen_bed" => 1}, "bathroom_count" => ["1", "4+"]}}
134
+ hash_dst = {"property" => {"bedroom_count" => ["1", "2"], "bathroom_count" => ["2"]}}
135
+ DeepMerge::deep_merge!(hash_src, hash_dst)
136
+ assert_equal({"property" => {"bedroom_count" => {"king_bed" => 3, "queen_bed" => 1}, "bathroom_count" => ["2","1","4+"]}}, hash_dst)
137
+
138
+ # hash holding hash holding hash v array (array is NOT overwritten by hash)
139
+ hash_src = {"property" => {"bedroom_count" => {"king_bed" => 3, "queen_bed" => 1}, "bathroom_count" => ["1", "4+"]}}
140
+ hash_dst = {"property" => {"bedroom_count" => ["1", "2"], "bathroom_count" => ["2"]}}
141
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:preserve_unmergeables => true})
142
+ assert_equal({"property" => {"bedroom_count" => ["1", "2"], "bathroom_count" => ["2","1","4+"]}}, hash_dst)
143
+
144
+ # 3 hash layers holding integers (integers are overwritten by source)
145
+ hash_src = {"property" => {"bedroom_count" => {"king_bed" => 3, "queen_bed" => 1}, "bathroom_count" => ["1", "4+"]}}
146
+ hash_dst = {"property" => {"bedroom_count" => {"king_bed" => 2, "queen_bed" => 4}, "bathroom_count" => ["2"]}}
147
+ DeepMerge::deep_merge!(hash_src, hash_dst)
148
+ assert_equal({"property" => {"bedroom_count" => {"king_bed" => 3, "queen_bed" => 1}, "bathroom_count" => ["2","1","4+"]}}, hash_dst)
149
+
150
+ # 3 hash layers holding arrays of int (arrays are merged)
151
+ hash_src = {"property" => {"bedroom_count" => {"king_bed" => [3], "queen_bed" => [1]}, "bathroom_count" => ["1", "4+"]}}
152
+ hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
153
+ DeepMerge::deep_merge!(hash_src, hash_dst)
154
+ assert_equal({"property" => {"bedroom_count" => {"king_bed" => [2,3], "queen_bed" => [4,1]}, "bathroom_count" => ["2","1","4+"]}}, hash_dst)
155
+
156
+ # 1 hash overwriting 3 hash layers holding arrays of int
157
+ hash_src = {"property" => "1"}
158
+ hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
159
+ DeepMerge::deep_merge!(hash_src, hash_dst)
160
+ assert_equal({"property" => "1"}, hash_dst)
161
+
162
+ # 1 hash NOT overwriting 3 hash layers holding arrays of int
163
+ hash_src = {"property" => "1"}
164
+ hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
165
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:preserve_unmergeables => true})
166
+ assert_equal({"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}, hash_dst)
167
+
168
+ # 3 hash layers holding arrays of int (arrays are merged) but second hash's array is overwritten
169
+ hash_src = {"property" => {"bedroom_count" => {"king_bed" => [3], "queen_bed" => [1]}, "bathroom_count" => "1"}}
170
+ hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
171
+ DeepMerge::deep_merge!(hash_src, hash_dst)
172
+ assert_equal({"property" => {"bedroom_count" => {"king_bed" => [2,3], "queen_bed" => [4,1]}, "bathroom_count" => "1"}}, hash_dst)
173
+
174
+ # 3 hash layers holding arrays of int (arrays are merged) but second hash's array is NOT overwritten
175
+ hash_src = {"property" => {"bedroom_count" => {"king_bed" => [3], "queen_bed" => [1]}, "bathroom_count" => "1"}}
176
+ hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
177
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:preserve_unmergeables => true})
178
+ assert_equal({"property" => {"bedroom_count" => {"king_bed" => [2,3], "queen_bed" => [4,1]}, "bathroom_count" => ["2"]}}, hash_dst)
179
+
180
+ # 3 hash layers holding arrays of int, but one holds int. This one overwrites, but the rest merge
181
+ hash_src = {"property" => {"bedroom_count" => {"king_bed" => 3, "queen_bed" => [1]}, "bathroom_count" => ["1"]}}
182
+ hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
183
+ DeepMerge::deep_merge!(hash_src, hash_dst)
184
+ assert_equal({"property" => {"bedroom_count" => {"king_bed" => 3, "queen_bed" => [4,1]}, "bathroom_count" => ["2","1"]}}, hash_dst)
185
+
186
+ # 3 hash layers holding arrays of int, but source is incomplete.
187
+ hash_src = {"property" => {"bedroom_count" => {"king_bed" => [3]}, "bathroom_count" => ["1"]}}
188
+ hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
189
+ DeepMerge::deep_merge!(hash_src, hash_dst)
190
+ assert_equal({"property" => {"bedroom_count" => {"king_bed" => [2,3], "queen_bed" => [4]}, "bathroom_count" => ["2","1"]}}, hash_dst)
191
+
192
+ # 3 hash layers holding arrays of int, but source is shorter and has new 2nd level ints.
193
+ hash_src = {"property" => {"bedroom_count" => {2=>3, "king_bed" => [3]}, "bathroom_count" => ["1"]}}
194
+ hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
195
+ DeepMerge::deep_merge!(hash_src, hash_dst)
196
+ assert_equal({"property" => {"bedroom_count" => {2=>3, "king_bed" => [2,3], "queen_bed" => [4]}, "bathroom_count" => ["2","1"]}}, hash_dst)
197
+
198
+ # 3 hash layers holding arrays of int, but source is empty
199
+ hash_src = {}
200
+ hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
201
+ DeepMerge::deep_merge!(hash_src, hash_dst)
202
+ assert_equal({"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}, hash_dst)
203
+
204
+ # 3 hash layers holding arrays of int, but dest is empty
205
+ hash_src = {"property" => {"bedroom_count" => {2=>3, "king_bed" => [3]}, "bathroom_count" => ["1"]}}
206
+ hash_dst = {}
207
+ DeepMerge::deep_merge!(hash_src, hash_dst)
208
+ assert_equal({"property" => {"bedroom_count" => {2=>3, "king_bed" => [3]}, "bathroom_count" => ["1"]}}, hash_dst)
209
+
210
+ # 3 hash layers holding arrays of int, but source includes a nil in the array
211
+ hash_src = {"property" => {"bedroom_count" => {"king_bed" => [nil], "queen_bed" => [1, nil]}, "bathroom_count" => [nil, "1"]}}
212
+ hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
213
+ DeepMerge::deep_merge!(hash_src, hash_dst)
214
+ assert_equal({"property" => {"bedroom_count" => {"king_bed" => [2,nil], "queen_bed" => [4, 1, nil]}, "bathroom_count" => ["2", nil, "1"]}}, hash_dst)
215
+
216
+ # 3 hash layers holding arrays of int, but destination includes a nil in the array
217
+ hash_src = {"property" => {"bedroom_count" => {"king_bed" => [3], "queen_bed" => [1]}, "bathroom_count" => ["1"]}}
218
+ hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [nil], "queen_bed" => [4, nil]}, "bathroom_count" => [nil,"2"]}}
219
+ DeepMerge::deep_merge!(hash_src, hash_dst)
220
+ assert_equal({"property" => {"bedroom_count" => {"king_bed" => [nil, 3], "queen_bed" => [4, nil, 1]}, "bathroom_count" => [nil, "2", "1"]}}, hash_dst)
221
+
222
+ # if extend_existig_arrays == true && destination.kind_of?(Array) && source element is neither array nor hash, push source to destionation
223
+ hash_src = { "property" => "4" }
224
+ hash_dst = { "property" => ["1", "2", "3"] }
225
+ DeepMerge::deep_merge!(hash_src, hash_dst, :extend_existing_arrays => true)
226
+ assert_equal({"property" => ["1", "2", "3", "4"]}, hash_dst)
227
+
228
+ # if extend_existig_arrays == true && destination.kind_of?(Array) && source.kind_of(Hash), push source to destionation
229
+ hash_src = { "property" => {:number => "3"} }
230
+ hash_dst = { "property" => [{:number => "1"}, {:number => "2"}] }
231
+ DeepMerge::deep_merge!(hash_src, hash_dst, :extend_existing_arrays => true)
232
+ assert_equal({"property"=>[{:number=>"1"}, {:number=>"2"}, {:number=>"3"}]}, hash_dst)
233
+
234
+ # test parameter management for knockout_prefix and overwrite unmergable
235
+ assert_raise(DeepMerge::InvalidParameter) {DeepMerge::deep_merge!(hash_src, hash_dst, {:knockout_prefix => ""})}
236
+ assert_raise(DeepMerge::InvalidParameter) {DeepMerge::deep_merge!(hash_src, hash_dst, {:preserve_unmergeables => true, :knockout_prefix => ""})}
237
+ assert_raise(DeepMerge::InvalidParameter) {DeepMerge::deep_merge!(hash_src, hash_dst, {:preserve_unmergeables => true, :knockout_prefix => "--"})}
238
+ assert_nothing_raised(DeepMerge::InvalidParameter) {DeepMerge::deep_merge!(hash_src, hash_dst, {:knockout_prefix => "--"})}
239
+ assert_nothing_raised(DeepMerge::InvalidParameter) {DeepMerge::deep_merge!(hash_src, hash_dst)}
240
+ assert_nothing_raised(DeepMerge::InvalidParameter) {DeepMerge::deep_merge!(hash_src, hash_dst, {:preserve_unmergeables => true})}
241
+
242
+ # hash holding arrays of arrays
243
+ hash_src = {["1", "2", "3"] => ["1", "2"]}
244
+ hash_dst = {["4", "5"] => ["3"]}
245
+ DeepMerge::deep_merge!(hash_src, hash_dst)
246
+ assert_equal({["1","2","3"] => ["1", "2"], ["4", "5"] => ["3"]}, hash_dst)
247
+
248
+ # test merging of hash with blank hash, and make sure that source array split still functions
249
+ hash_src = {'property' => {'bedroom_count' => ["1","2,3"]}}
250
+ hash_dst = {}
251
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ","})
252
+ assert_equal({'property' => {'bedroom_count' => ["1","2","3"]}}, hash_dst)
253
+
254
+ # test merging of hash with blank hash, and make sure that source array split does not function when turned off
255
+ hash_src = {'property' => {'bedroom_count' => ["1","2,3"]}}
256
+ hash_dst = {}
257
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX})
258
+ assert_equal({'property' => {'bedroom_count' => ["1","2,3"]}}, hash_dst)
259
+
260
+ # test merging into a blank hash with overwrite_unmergeables turned on
261
+ hash_src = {"action"=>"browse", "controller"=>"results"}
262
+ hash_dst = {}
263
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:overwrite_unmergeables => true, :knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ","})
264
+ assert_equal hash_src, hash_dst
265
+
266
+ # KNOCKOUT_PREFIX testing
267
+ # the next few tests are looking for correct behavior from specific real-world params/session merges
268
+ # using the custom modifiers built for param/session merges
269
+
270
+ [nil, ","].each do |ko_split|
271
+ # typical params/session style hash with knockout_merge elements
272
+ hash_params = {"property"=>{"bedroom_count"=>[FIELD_KNOCKOUT_PREFIX+"1", "2", "3"]}}
273
+ hash_session = {"property"=>{"bedroom_count"=>["1", "2", "3"]}}
274
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ko_split})
275
+ assert_equal({"property"=>{"bedroom_count"=>["2", "3"]}}, hash_session)
276
+
277
+ # typical params/session style hash with knockout_merge elements
278
+ hash_params = {"property"=>{"bedroom_count"=>[FIELD_KNOCKOUT_PREFIX+"1", "2", "3"]}}
279
+ hash_session = {"property"=>{"bedroom_count"=>["3"]}}
280
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ko_split})
281
+ assert_equal({"property"=>{"bedroom_count"=>["3","2"]}}, hash_session)
282
+
283
+ # typical params/session style hash with knockout_merge elements
284
+ hash_params = {"property"=>{"bedroom_count"=>[FIELD_KNOCKOUT_PREFIX+"1", "2", "3"]}}
285
+ hash_session = {"property"=>{"bedroom_count"=>["4"]}}
286
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ko_split})
287
+ assert_equal({"property"=>{"bedroom_count"=>["4","2","3"]}}, hash_session)
288
+
289
+ # typical params/session style hash with knockout_merge elements
290
+ hash_params = {"property"=>{"bedroom_count"=>[FIELD_KNOCKOUT_PREFIX+"1", "2", "3"]}}
291
+ hash_session = {"property"=>{"bedroom_count"=>[FIELD_KNOCKOUT_PREFIX+"1", "4"]}}
292
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ko_split})
293
+ assert_equal({"property"=>{"bedroom_count"=>["4","2","3"]}}, hash_session)
294
+
295
+ # typical params/session style hash with knockout_merge elements
296
+ hash_params = {"amenity"=>{"id"=>[FIELD_KNOCKOUT_PREFIX+"1", FIELD_KNOCKOUT_PREFIX+"2", "3", "4"]}}
297
+ hash_session = {"amenity"=>{"id"=>["1", "2"]}}
298
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ko_split})
299
+ assert_equal({"amenity"=>{"id"=>["3","4"]}}, hash_session)
300
+ end
301
+
302
+ # special params/session style hash with knockout_merge elements in form src: ["1","2"] dest:["--1,--2", "3,4"]
303
+ hash_params = {"amenity"=>{"id"=>[FIELD_KNOCKOUT_PREFIX+"1,"+FIELD_KNOCKOUT_PREFIX+"2", "3,4"]}}
304
+ hash_session = {"amenity"=>{"id"=>["1", "2"]}}
305
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ","})
306
+ assert_equal({"amenity"=>{"id"=>["3","4"]}}, hash_session)
307
+
308
+ # same as previous but without ko_split value, this merge should fail
309
+ hash_params = {"amenity"=>{"id"=>[FIELD_KNOCKOUT_PREFIX+"1,"+FIELD_KNOCKOUT_PREFIX+"2", "3,4"]}}
310
+ hash_session = {"amenity"=>{"id"=>["1", "2"]}}
311
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX})
312
+ assert_equal({"amenity"=>{"id"=>["1","2","3,4"]}}, hash_session)
313
+
314
+ # special params/session style hash with knockout_merge elements in form src: ["1","2"] dest:["--1,--2", "3,4"]
315
+ hash_params = {"amenity"=>{"id"=>[FIELD_KNOCKOUT_PREFIX+"1,2", "3,4", "--5", "6"]}}
316
+ hash_session = {"amenity"=>{"id"=>["1", "2"]}}
317
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ","})
318
+ assert_equal({"amenity"=>{"id"=>["2","3","4","6"]}}, hash_session)
319
+
320
+ # special params/session style hash with knockout_merge elements in form src: ["--1,--2", "3,4", "--5", "6"] dest:["1,2", "3,4"]
321
+ hash_params = {"amenity"=>{"id"=>["#{FIELD_KNOCKOUT_PREFIX}1,#{FIELD_KNOCKOUT_PREFIX}2", "3,4", "#{FIELD_KNOCKOUT_PREFIX}5", "6"]}}
322
+ hash_session = {"amenity"=>{"id"=>["1", "2", "3", "4"]}}
323
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ","})
324
+ assert_equal({"amenity"=>{"id"=>["3","4","6"]}}, hash_session)
325
+
326
+
327
+ hash_src = {"url_regions"=>[], "region"=>{"ids"=>["227,233"]}, "action"=>"browse", "task"=>"browse", "controller"=>"results"}
328
+ hash_dst = {"region"=>{"ids"=>["227"]}}
329
+ DeepMerge::deep_merge!(hash_src.dup, hash_dst, {:overwrite_unmergeables => true, :knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ","})
330
+ assert_equal({"url_regions"=>[], "region"=>{"ids"=>["227","233"]}, "action"=>"browse", "task"=>"browse", "controller"=>"results"}, hash_dst)
331
+
332
+ hash_src = {"region"=>{"ids"=>["--","227"], "id"=>"230"}}
333
+ hash_dst = {"region"=>{"ids"=>["227", "233", "324", "230", "230"], "id"=>"230"}}
334
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:overwrite_unmergeables => true, :knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ","})
335
+ assert_equal({"region"=>{"ids"=>["227"], "id"=>"230"}}, hash_dst)
336
+
337
+ hash_src = {"region"=>{"ids"=>["--","227", "232", "233"], "id"=>"232"}}
338
+ hash_dst = {"region"=>{"ids"=>["227", "233", "324", "230", "230"], "id"=>"230"}}
339
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:overwrite_unmergeables => true, :knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ","})
340
+ assert_equal({"region"=>{"ids"=>["227", "232", "233"], "id"=>"232"}}, hash_dst)
341
+
342
+ hash_src = {"region"=>{"ids"=>["--,227,232,233"], "id"=>"232"}}
343
+ hash_dst = {"region"=>{"ids"=>["227", "233", "324", "230", "230"], "id"=>"230"}}
344
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:overwrite_unmergeables => true, :knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ","})
345
+ assert_equal({"region"=>{"ids"=>["227", "232", "233"], "id"=>"232"}}, hash_dst)
346
+
347
+ hash_src = {"region"=>{"ids"=>["--,227,232","233"], "id"=>"232"}}
348
+ hash_dst = {"region"=>{"ids"=>["227", "233", "324", "230", "230"], "id"=>"230"}}
349
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:overwrite_unmergeables => true, :knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ","})
350
+ assert_equal({"region"=>{"ids"=>["227", "232", "233"], "id"=>"232"}}, hash_dst)
351
+
352
+ hash_src = {"region"=>{"ids"=>["--,227"], "id"=>"230"}}
353
+ hash_dst = {"region"=>{"ids"=>["227", "233", "324", "230", "230"], "id"=>"230"}}
354
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:overwrite_unmergeables => true, :knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ","})
355
+ assert_equal({"region"=>{"ids"=>["227"], "id"=>"230"}}, hash_dst)
356
+
357
+ hash_src = {"region"=>{"ids"=>["--,227"], "id"=>"230"}}
358
+ hash_dst = {"region"=>{"ids"=>["227", "233", "324", "230", "230"], "id"=>"230"}, "action"=>"browse", "task"=>"browse", "controller"=>"results", "property_order_by"=>"property_type.descr"}
359
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:overwrite_unmergeables => true, :knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ","})
360
+ assert_equal({"region"=>{"ids"=>["227"], "id"=>"230"}, "action"=>"browse", "task"=>"browse",
361
+ "controller"=>"results", "property_order_by"=>"property_type.descr"}, hash_dst)
362
+
363
+ hash_src = {"query_uuid"=>"6386333d-389b-ab5c-8943-6f3a2aa914d7", "region"=>{"ids"=>["--,227"], "id"=>"230"}}
364
+ hash_dst = {"query_uuid"=>"6386333d-389b-ab5c-8943-6f3a2aa914d7", "url_regions"=>[], "region"=>{"ids"=>["227", "233", "324", "230", "230"], "id"=>"230"}, "action"=>"browse", "task"=>"browse", "controller"=>"results", "property_order_by"=>"property_type.descr"}
365
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:overwrite_unmergeables => true, :knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ","})
366
+ assert_equal({"query_uuid" => "6386333d-389b-ab5c-8943-6f3a2aa914d7", "url_regions"=>[],
367
+ "region"=>{"ids"=>["227"], "id"=>"230"}, "action"=>"browse", "task"=>"browse",
368
+ "controller"=>"results", "property_order_by"=>"property_type.descr"}, hash_dst)
369
+
370
+ # knock out entire dest hash if "--" is passed for source
371
+ hash_params = {'amenity' => "--"}
372
+ hash_session = {"amenity" => "1"}
373
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => "--", :unpack_arrays => ","})
374
+ assert_equal({'amenity' => ""}, hash_session)
375
+
376
+ # knock out entire dest hash if "--" is passed for source
377
+ hash_params = {'amenity' => ["--"]}
378
+ hash_session = {"amenity" => "1"}
379
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => "--", :unpack_arrays => ","})
380
+ assert_equal({'amenity' => []}, hash_session)
381
+
382
+ # knock out entire dest hash if "--" is passed for source
383
+ hash_params = {'amenity' => "--"}
384
+ hash_session = {"amenity" => ["1"]}
385
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => "--", :unpack_arrays => ","})
386
+ assert_equal({'amenity' => ""}, hash_session)
387
+
388
+ # knock out entire dest hash if "--" is passed for source
389
+ hash_params = {'amenity' => ["--"]}
390
+ hash_session = {"amenity" => ["1"]}
391
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => "--", :unpack_arrays => ","})
392
+ assert_equal({'amenity' => []}, hash_session)
393
+
394
+ # knock out entire dest hash if "--" is passed for source
395
+ hash_params = {'amenity' => ["--"]}
396
+ hash_session = {"amenity" => "1"}
397
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => "--", :unpack_arrays => ","})
398
+ assert_equal({'amenity' => []}, hash_session)
399
+
400
+ # knock out entire dest hash if "--" is passed for source
401
+ hash_params = {'amenity' => ["--", "2"]}
402
+ hash_session = {'amenity' => ["1", "3", "7+"]}
403
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => "--", :unpack_arrays => ","})
404
+ assert_equal({'amenity' => ["2"]}, hash_session)
405
+
406
+ # knock out entire dest hash if "--" is passed for source
407
+ hash_params = {'amenity' => ["--", "2"]}
408
+ hash_session = {'amenity' => "5"}
409
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => "--", :unpack_arrays => ","})
410
+ assert_equal({'amenity' => ['2']}, hash_session)
411
+
412
+ # knock out entire dest hash if "--" is passed for source
413
+ hash_params = {'amenity' => "--"}
414
+ hash_session = {"amenity"=>{"id"=>["1", "2", "3", "4"]}}
415
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => "--", :unpack_arrays => ","})
416
+ assert_equal({'amenity' => ""}, hash_session)
417
+
418
+ # knock out entire dest hash if "--" is passed for source
419
+ hash_params = {'amenity' => ["--"]}
420
+ hash_session = {"amenity"=>{"id"=>["1", "2", "3", "4"]}}
421
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => "--", :unpack_arrays => ","})
422
+ assert_equal({'amenity' => []}, hash_session)
423
+
424
+ # knock out dest array if "--" is passed for source
425
+ hash_params = {"region" => {'ids' => FIELD_KNOCKOUT_PREFIX}}
426
+ hash_session = {"region"=>{"ids"=>["1", "2", "3", "4"]}}
427
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ","})
428
+ assert_equal({'region' => {'ids' => ""}}, hash_session)
429
+
430
+ # knock out dest array but leave other elements of hash intact
431
+ hash_params = {"region" => {'ids' => FIELD_KNOCKOUT_PREFIX}}
432
+ hash_session = {"region"=>{"ids"=>["1", "2", "3", "4"], 'id'=>'11'}}
433
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ","})
434
+ assert_equal({'region' => {'ids' => "", 'id'=>'11'}}, hash_session)
435
+
436
+ # knock out entire tree of dest hash
437
+ hash_params = {"region" => FIELD_KNOCKOUT_PREFIX}
438
+ hash_session = {"region"=>{"ids"=>["1", "2", "3", "4"], 'id'=>'11'}}
439
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ","})
440
+ assert_equal({'region' => ""}, hash_session)
441
+
442
+ # knock out entire tree of dest hash - retaining array format
443
+ hash_params = {"region" => {'ids' => [FIELD_KNOCKOUT_PREFIX]}}
444
+ hash_session = {"region"=>{"ids"=>["1", "2", "3", "4"], 'id'=>'11'}}
445
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ","})
446
+ assert_equal({'region' => {'ids' => [], 'id'=>'11'}}, hash_session)
447
+
448
+ # knock out entire tree of dest hash & replace with new content
449
+ hash_params = {"region" => {'ids' => ["2", FIELD_KNOCKOUT_PREFIX, "6"]}}
450
+ hash_session = {"region"=>{"ids"=>["1", "2", "3", "4"], 'id'=>'11'}}
451
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ","})
452
+ assert_equal({'region' => {'ids' => ["2", "6"], 'id'=>'11'}}, hash_session)
453
+
454
+ # knock out entire tree of dest hash & replace with new content
455
+ hash_params = {"region" => {'ids' => ["7", FIELD_KNOCKOUT_PREFIX, "6"]}}
456
+ hash_session = {"region"=>{"ids"=>["1", "2", "3", "4"], 'id'=>'11'}}
457
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ","})
458
+ assert_equal({'region' => {'ids' => ["7", "6"], 'id'=>'11'}}, hash_session)
459
+
460
+ # edge test: make sure that when we turn off knockout_prefix that all values are processed correctly
461
+ hash_params = {"region" => {'ids' => ["7", "--", "2", "6,8"]}}
462
+ hash_session = {"region"=>{"ids"=>["1", "2", "3", "4"], 'id'=>'11'}}
463
+ DeepMerge::deep_merge!(hash_params, hash_session, {:unpack_arrays => ","})
464
+ assert_equal({'region' => {'ids' => ["1", "2", "3", "4", "7", "--", "6", "8"], 'id'=>'11'}}, hash_session)
465
+
466
+ # edge test 2: make sure that when we turn off source array split that all values are processed correctly
467
+ hash_params = {"region" => {'ids' => ["7", "3", "--", "6,8"]}}
468
+ hash_session = {"region"=>{"ids"=>["1", "2", "3", "4"], 'id'=>'11'}}
469
+ DeepMerge::deep_merge!(hash_params, hash_session)
470
+ assert_equal({'region' => {'ids' => ["1", "2", "3", "4", "7", "--", "6,8"], 'id'=>'11'}}, hash_session)
471
+
472
+ # Example: src = {'key' => "--1"}, dst = {'key' => "1"} -> merges to {'key' => ""}
473
+ hash_params = {"amenity"=>"--1"}
474
+ hash_session = {"amenity"=>"1"}
475
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX})
476
+ assert_equal({"amenity"=>""}, hash_session)
477
+
478
+ # Example: src = {'key' => "--1"}, dst = {'key' => "2"} -> merges to {'key' => ""}
479
+ hash_params = {"amenity"=>"--1"}
480
+ hash_session = {"amenity"=>"2"}
481
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX})
482
+ assert_equal({"amenity"=>""}, hash_session)
483
+
484
+ # Example: src = {'key' => "--1"}, dst = {'key' => "1"} -> merges to {'key' => ""}
485
+ hash_params = {"amenity"=>["--1"]}
486
+ hash_session = {"amenity"=>"1"}
487
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX})
488
+ assert_equal({"amenity"=>[]}, hash_session)
489
+
490
+ # Example: src = {'key' => "--1"}, dst = {'key' => "1"} -> merges to {'key' => ""}
491
+ hash_params = {"amenity"=>["--1"]}
492
+ hash_session = {"amenity"=>["1"]}
493
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX})
494
+ assert_equal({"amenity"=>[]}, hash_session)
495
+
496
+ # Example: src = {'key' => "--1"}, dst = {'key' => "1"} -> merges to {'key' => ""}
497
+ hash_params = {"amenity"=>"--1"}
498
+ hash_session = {}
499
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX})
500
+ assert_equal({"amenity"=>""}, hash_session)
501
+
502
+
503
+ # Example: src = {'key' => "--1"}, dst = {'key' => "1"} -> merges to {'key' => ""}
504
+ hash_params = {"amenity"=>"--1"}
505
+ hash_session = {"amenity"=>["1"]}
506
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX})
507
+ assert_equal({"amenity"=>""}, hash_session)
508
+
509
+ #are unmerged hashes passed unmodified w/out :unpack_arrays?
510
+ hash_params = {"amenity"=>{"id"=>["26,27"]}}
511
+ hash_session = {}
512
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX})
513
+ assert_equal({"amenity"=>{"id"=>["26,27"]}}, hash_session)
514
+
515
+ #hash should be merged
516
+ hash_params = {"amenity"=>{"id"=>["26,27"]}}
517
+ hash_session = {}
518
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ","})
519
+ assert_equal({"amenity"=>{"id"=>["26","27"]}}, hash_session)
520
+
521
+ # second merge of same values should result in no change in output
522
+ hash_params = {"amenity"=>{"id"=>["26,27"]}}
523
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ","})
524
+ assert_equal({"amenity"=>{"id"=>["26","27"]}}, hash_session)
525
+
526
+ #hashes with knockout values are suppressed
527
+ hash_params = {"amenity"=>{"id"=>["#{FIELD_KNOCKOUT_PREFIX}26,#{FIELD_KNOCKOUT_PREFIX}27,28"]}}
528
+ hash_session = {}
529
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ","})
530
+ assert_equal({"amenity"=>{"id"=>["28"]}}, hash_session)
531
+
532
+ hash_src= {'region' =>{'ids'=>['--']}, 'query_uuid' => 'zzz'}
533
+ hash_dst= {'region' =>{'ids'=>['227','2','3','3']}, 'query_uuid' => 'zzz'}
534
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:knockout_prefix => '--', :unpack_arrays => ","})
535
+ assert_equal({'region' =>{'ids'=>[]}, 'query_uuid' => 'zzz'}, hash_dst)
536
+
537
+ hash_src= {'region' =>{'ids'=>['--']}, 'query_uuid' => 'zzz'}
538
+ hash_dst= {'region' =>{'ids'=>['227','2','3','3'], 'id' => '3'}, 'query_uuid' => 'zzz'}
539
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:knockout_prefix => '--', :unpack_arrays => ","})
540
+ assert_equal({'region' =>{'ids'=>[], 'id'=>'3'}, 'query_uuid' => 'zzz'}, hash_dst)
541
+
542
+ hash_src= {'region' =>{'ids'=>['--']}, 'query_uuid' => 'zzz'}
543
+ hash_dst= {'region' =>{'muni_city_id' => '2244', 'ids'=>['227','2','3','3'], 'id'=>'3'}, 'query_uuid' => 'zzz'}
544
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:knockout_prefix => '--', :unpack_arrays => ","})
545
+ assert_equal({'region' =>{'muni_city_id' => '2244', 'ids'=>[], 'id'=>'3'}, 'query_uuid' => 'zzz'}, hash_dst)
546
+
547
+ hash_src= {'region' =>{'ids'=>['--'], 'id' => '5'}, 'query_uuid' => 'zzz'}
548
+ hash_dst= {'region' =>{'muni_city_id' => '2244', 'ids'=>['227','2','3','3'], 'id'=>'3'}, 'query_uuid' => 'zzz'}
549
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:knockout_prefix => '--', :unpack_arrays => ","})
550
+ assert_equal({'region' =>{'muni_city_id' => '2244', 'ids'=>[], 'id'=>'5'}, 'query_uuid' => 'zzz'}, hash_dst)
551
+
552
+ hash_src= {'region' =>{'ids'=>['--', '227'], 'id' => '5'}, 'query_uuid' => 'zzz'}
553
+ hash_dst= {'region' =>{'muni_city_id' => '2244', 'ids'=>['227','2','3','3'], 'id'=>'3'}, 'query_uuid' => 'zzz'}
554
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:knockout_prefix => '--', :unpack_arrays => ","})
555
+ assert_equal({'region' =>{'muni_city_id' => '2244', 'ids'=>['227'], 'id'=>'5'}, 'query_uuid' => 'zzz'}, hash_dst)
556
+
557
+ hash_src= {'region' =>{'muni_city_id' => '--', 'ids'=>'--', 'id'=>'5'}, 'query_uuid' => 'zzz'}
558
+ hash_dst= {'region' =>{'muni_city_id' => '2244', 'ids'=>['227','2','3','3'], 'id'=>'3'}, 'query_uuid' => 'zzz'}
559
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:knockout_prefix => '--', :unpack_arrays => ","})
560
+ assert_equal({'region' =>{'muni_city_id' => '', 'ids'=>'', 'id'=>'5'}, 'query_uuid' => 'zzz'}, hash_dst)
561
+
562
+ hash_src= {'region' =>{'muni_city_id' => '--', 'ids'=>['--'], 'id'=>'5'}, 'query_uuid' => 'zzz'}
563
+ hash_dst= {'region' =>{'muni_city_id' => '2244', 'ids'=>['227','2','3','3'], 'id'=>'3'}, 'query_uuid' => 'zzz'}
564
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:knockout_prefix => '--', :unpack_arrays => ","})
565
+ assert_equal({'region' =>{'muni_city_id' => '', 'ids'=>[], 'id'=>'5'}, 'query_uuid' => 'zzz'}, hash_dst)
566
+
567
+ hash_src= {'region' =>{'muni_city_id' => '--', 'ids'=>['--','227'], 'id'=>'5'}, 'query_uuid' => 'zzz'}
568
+ hash_dst= {'region' =>{'muni_city_id' => '2244', 'ids'=>['227','2','3','3'], 'id'=>'3'}, 'query_uuid' => 'zzz'}
569
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:knockout_prefix => '--', :unpack_arrays => ","})
570
+ assert_equal({'region' =>{'muni_city_id' => '', 'ids'=>['227'], 'id'=>'5'}, 'query_uuid' => 'zzz'}, hash_dst)
571
+
572
+ hash_src = {"muni_city_id"=>"--", "id"=>""}
573
+ hash_dst = {"muni_city_id"=>"", "id"=>""}
574
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:knockout_prefix => '--', :unpack_arrays => ","})
575
+ assert_equal({"muni_city_id"=>"", "id"=>""}, hash_dst)
576
+
577
+ hash_src = {"region"=>{"muni_city_id"=>"--", "id"=>""}}
578
+ hash_dst = {"region"=>{"muni_city_id"=>"", "id"=>""}}
579
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:knockout_prefix => '--', :unpack_arrays => ","})
580
+ assert_equal({"region"=>{"muni_city_id"=>"", "id"=>""}}, hash_dst)
581
+
582
+ hash_src = {"query_uuid"=>"a0dc3c84-ec7f-6756-bdb0-fff9157438ab", "url_regions"=>[], "region"=>{"muni_city_id"=>"--", "id"=>""}, "property"=>{"property_type_id"=>"", "search_rate_min"=>"", "search_rate_max"=>""}, "task"=>"search", "run_query"=>"Search"}
583
+ hash_dst = {"query_uuid"=>"a0dc3c84-ec7f-6756-bdb0-fff9157438ab", "url_regions"=>[], "region"=>{"muni_city_id"=>"", "id"=>""}, "property"=>{"property_type_id"=>"", "search_rate_min"=>"", "search_rate_max"=>""}, "task"=>"search", "run_query"=>"Search"}
584
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:knockout_prefix => '--', :unpack_arrays => ","})
585
+ assert_equal({"query_uuid"=>"a0dc3c84-ec7f-6756-bdb0-fff9157438ab", "url_regions"=>[], "region"=>{"muni_city_id"=>"", "id"=>""}, "property"=>{"property_type_id"=>"", "search_rate_min"=>"", "search_rate_max"=>""}, "task"=>"search", "run_query"=>"Search"}, hash_dst)
586
+
587
+ # hash of array of hashes
588
+ hash_src = {"item" => [{"1" => "3"}, {"2" => "4"}]}
589
+ hash_dst = {"item" => [{"3" => "5"}]}
590
+ DeepMerge::deep_merge!(hash_src, hash_dst)
591
+ assert_equal({"item" => [{"3" => "5"}, {"1" => "3"}, {"2" => "4"}]}, hash_dst)
592
+
593
+ ######################################
594
+ # tests for "merge_hash_arrays" option
595
+
596
+ hash_src = {"item" => [{"1" => "3"}]}
597
+ hash_dst = {"item" => [{"3" => "5"}]}
598
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:merge_hash_arrays => true})
599
+ assert_equal({"item" => [{"3" => "5", "1" => "3"}]}, hash_dst)
600
+
601
+ hash_src = {"item" => [{"1" => "3"}, {"2" => "4"}]}
602
+ hash_dst = {"item" => [{"3" => "5"}]}
603
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:merge_hash_arrays => true})
604
+ assert_equal({"item" => [{"3" => "5", "1" => "3"}, {"2" => "4"}]}, hash_dst)
605
+
606
+ hash_src = {"item" => [{"1" => "3"}]}
607
+ hash_dst = {"item" => [{"3" => "5"}, {"2" => "4"}]}
608
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:merge_hash_arrays => true})
609
+ assert_equal({"item" => [{"3" => "5", "1" => "3"}, {"2" => "4"}]}, hash_dst)
610
+
611
+ # if arrays contain non-hash objects, the :merge_hash_arrays option has
612
+ # no effect.
613
+ hash_src = {"item" => [{"1" => "3"}, "str"]} # contains "str", non-hash
614
+ hash_dst = {"item" => [{"3" => "5"}]}
615
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:merge_hash_arrays => true})
616
+ assert_equal({"item" => [{"3" => "5"}, {"1" => "3"}, "str"]}, hash_dst)
617
+
618
+ # Merging empty strings
619
+ s1, s2 = "hello", ""
620
+ [s1, s2].each { |s| s.extend StringBlank }
621
+ hash_dst = {"item" => s1 }
622
+ hash_src = {"item" => s2 }
623
+ DeepMerge::deep_merge!(hash_src, hash_dst)
624
+ assert_equal({"item" => ""}, hash_dst)
625
+ end # test_deep_merge
626
+ end
metadata ADDED
@@ -0,0 +1,70 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: deep_merge2
3
+ version: !ruby/object:Gem::Version
4
+ version: '1.0'
5
+ platform: ruby
6
+ authors:
7
+ - Steve Midgley
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2011-07-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '10.1'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '10.1'
27
+ description: Recursively merge hashes. Now works with Ruby 1.9 and ActiveSupport
28
+ email: dan@kallistec.com
29
+ executables: []
30
+ extensions: []
31
+ extra_rdoc_files:
32
+ - LICENSE
33
+ - README.md
34
+ files:
35
+ - CHANGELOG
36
+ - LICENSE
37
+ - README.md
38
+ - Rakefile
39
+ - lib/deep_merge.rb
40
+ - lib/deep_merge/core.rb
41
+ - lib/deep_merge/deep_merge_hash.rb
42
+ - lib/deep_merge/rails_compat.rb
43
+ - test/test_deep_merge.rb
44
+ homepage: https://github.com/danielsdeleo/deep_merge
45
+ licenses:
46
+ - MIT
47
+ metadata: {}
48
+ post_install_message:
49
+ rdoc_options: []
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ required_rubygems_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ requirements: []
63
+ rubyforge_project:
64
+ rubygems_version: 2.4.5
65
+ signing_key:
66
+ specification_version: 4
67
+ summary: Merge Deeply Nested Hashes
68
+ test_files:
69
+ - test/test_deep_merge.rb
70
+ has_rdoc: