monkey_forms 0.0.16 → 0.0.17

Sign up to get free protection for your applications and to get access to all the features.
Files changed (25) hide show
  1. data/lib/monkey_forms/vendor/deep_merge/.gitignore +2 -0
  2. data/lib/monkey_forms/vendor/deep_merge/CHANGELOG +34 -0
  3. data/lib/monkey_forms/vendor/deep_merge/README +88 -0
  4. data/lib/monkey_forms/vendor/deep_merge/Rakefile +20 -0
  5. data/lib/monkey_forms/vendor/deep_merge/VERSION +1 -0
  6. data/lib/monkey_forms/vendor/deep_merge/lib/deep_merge.rb +2 -0
  7. data/lib/monkey_forms/vendor/deep_merge/lib/deep_merge/core.rb +187 -0
  8. data/lib/monkey_forms/vendor/deep_merge/lib/deep_merge/deep_merge_hash.rb +28 -0
  9. data/lib/monkey_forms/vendor/deep_merge/lib/deep_merge/rails_compat.rb +27 -0
  10. data/lib/monkey_forms/vendor/deep_merge/test/test_deep_merge.rb +572 -0
  11. data/lib/monkey_forms/vendor/grouped_validations/.gitignore +3 -0
  12. data/lib/monkey_forms/vendor/grouped_validations/.rspec +2 -0
  13. data/lib/monkey_forms/vendor/grouped_validations/Gemfile +7 -0
  14. data/lib/monkey_forms/vendor/grouped_validations/MIT-LICENSE +20 -0
  15. data/lib/monkey_forms/vendor/grouped_validations/README.rdoc +146 -0
  16. data/lib/monkey_forms/vendor/grouped_validations/Rakefile +26 -0
  17. data/lib/monkey_forms/vendor/grouped_validations/grouped_validations.gemspec +23 -0
  18. data/lib/monkey_forms/vendor/grouped_validations/init.rb +1 -0
  19. data/lib/monkey_forms/vendor/grouped_validations/lib/grouped_validations.rb +93 -0
  20. data/lib/monkey_forms/vendor/grouped_validations/lib/grouped_validations/active_model.rb +34 -0
  21. data/lib/monkey_forms/vendor/grouped_validations/lib/grouped_validations/version.rb +3 -0
  22. data/lib/monkey_forms/vendor/grouped_validations/spec/grouped_validations_spec.rb +252 -0
  23. data/lib/monkey_forms/vendor/grouped_validations/spec/spec_helper.rb +32 -0
  24. data/lib/monkey_forms/version.rb +1 -1
  25. metadata +42 -19
@@ -0,0 +1,2 @@
1
+ pkg/*
2
+ *.gemspec
@@ -0,0 +1,34 @@
1
+ 2011-05-23 Joe Van Dyk <joe@fixieconsulting.com>
2
+
3
+ * Added Changelog
4
+
5
+ 2011-05-18 Joe Van Dyk <joe@fixieconsulting.com>
6
+
7
+ * Merging empty strings should work if String#blank? is defined.
8
+
9
+ * Use unix line endings
10
+
11
+ * Removing extra whitespace
12
+
13
+ 2010-01-11 Dan DeLeo <danielsdeleo@mac.com>
14
+
15
+ * fix boolean merging according to mdkent's patch explicitly test
16
+ for nils w/ #nil? instead of negating. Thanks mdkent!
17
+
18
+ 2009-12-25 Dan DeLeo <danielsdeleo@mac.com>
19
+
20
+ * miscellaneous cleanup
21
+
22
+ * make rails/active_support compat optional
23
+
24
+ * add jeweler rake task for gemability
25
+
26
+ 2009-12-24 Dan DeLeo <danielsdeleo@mac.com>
27
+
28
+ * VERSION: Version bump to 0.0.1
29
+
30
+ * VERSION: Version bump to 0.0.0
31
+
32
+ 2009-11-06 Jonathan Weiss <jw@innerewut.de>
33
+
34
+ * import
@@ -0,0 +1,88 @@
1
+ DeepMerge Overview
2
+ ==================
3
+
4
+ Deep Merge is a simple set of utility functions for Hash. It permits
5
+ you to merge elements inside a hash together recursively. The manner
6
+ by which it does this is somewhat arbitrary (since there is no defining
7
+ standard for this) but it should end up being pretty intuitive and do what
8
+ you expect.
9
+
10
+ You can learn a lot more about this by reading the test file. It's pretty
11
+ well documented and has many examples of various merges from very simple
12
+ to pretty complex.
13
+
14
+ The primary need that caused me to write this library is the merging of elements
15
+ coming from HTTP parameters and related stored parameters in session. This lets
16
+ a user build up a set of parameters over time, modifying individual items.
17
+
18
+ Deep Merge Core Documentation
19
+ =============================
20
+ deep_merge! method permits merging of arbitrary child elements. The two top level
21
+ elements must be hashes. These hashes can contain unlimited (to stack limit) levels
22
+ of child elements. These child elements to not have to be of the same types.
23
+ Where child elements are of the same type, deep_merge will attempt to merge them together.
24
+ Where child elements are not of the same type, deep_merge will skip or optionally overwrite
25
+ the destination element with the contents of the source element at that level.
26
+ So if you have two hashes like this:
27
+ source = {:x => [1,2,3], :y => 2}
28
+ dest = {:x => [4,5,'6'], :y => [7,8,9]}
29
+ dest.deep_merge!(source)
30
+ Results: {:x => [1,2,3,4,5,'6'], :y => 2}
31
+ By default, "deep_merge!" will overwrite any unmergeables and merge everything else.
32
+ To avoid this, use "deep_merge" (no bang/exclamation mark)
33
+
34
+ Options:
35
+ Options are specified in the last parameter passed, which should be in hash format:
36
+ hash.deep_merge!({:x => [1,2]}, {:knockout_prefix => '--'})
37
+ :preserve_unmergeables DEFAULT: false
38
+ Set to true to skip any unmergeable elements from source
39
+ :knockout_prefix DEFAULT: nil
40
+ Set to string value to signify prefix which deletes elements from existing element
41
+ :sort_merged_arrays DEFAULT: false
42
+ Set to true to sort all arrays that are merged together
43
+ :unpack_arrays DEFAULT: nil
44
+ Set to string value to run "Array::join" then "String::split" against all arrays
45
+ :merge_debug DEFAULT: false
46
+ Set to true to get console output of merge process for debugging
47
+
48
+ Selected Options Details:
49
+ :knockout_prefix => The purpose of this is to provide a way to remove elements
50
+ from existing Hash by specifying them in a special way in incoming hash
51
+ source = {:x => ['--1', '2']}
52
+ dest = {:x => ['1', '3']}
53
+ dest.ko_deep_merge!(source)
54
+ Results: {:x => ['2','3']}
55
+ Additionally, if the knockout_prefix is passed alone as a string, it will cause
56
+ the entire element to be removed:
57
+ source = {:x => '--'}
58
+ dest = {:x => [1,2,3]}
59
+ dest.ko_deep_merge!(source)
60
+ Results: {:x => ""}
61
+ :unpack_arrays => The purpose of this is to permit compound elements to be passed
62
+ in as strings and to be converted into discrete array elements
63
+ irsource = {:x => ['1,2,3', '4']}
64
+ dest = {:x => ['5','6','7,8']}
65
+ dest.deep_merge!(source, {:unpack_arrays => ','})
66
+ Results: {:x => ['1','2','3','4','5','6','7','8'}
67
+ Why: If receiving data from an HTML form, this makes it easy for a checkbox
68
+ to pass multiple values from within a single HTML element
69
+
70
+ There are many tests for this library - and you can learn more about the features
71
+ and usages of deep_merge! by just browsing the test examples
72
+
73
+
74
+ Simple Example Code
75
+ ===================
76
+
77
+ require 'deep_merge'
78
+ x = {:x => [3,4,5]}
79
+ y = {:x => [1,2,3]}
80
+ y.deep_merge!(x)
81
+ # results: y = {:x => [1,2,3,4,5]}
82
+
83
+ Availablility
84
+ =============
85
+ SVN Repo here: http://trac.misuse.org/science/wiki/DeepMerge
86
+ Contact author: http://www.misuse.org/science
87
+
88
+ Copyright (c) 2008 Steve Midgley, released under the MIT license
@@ -0,0 +1,20 @@
1
+
2
+ begin
3
+ require 'rubygems'
4
+ rescue LoadError
5
+ #okay, then
6
+ end
7
+
8
+ begin
9
+ require 'jeweler'
10
+ Jeweler::Tasks.new do |gemspec|
11
+ gemspec.name = "deep_merge"
12
+ gemspec.summary = "Merge Deeply Nested Hashes"
13
+ gemspec.description = "The Peritor Fork of deep_merge, with Ruby 1.9 and ActiveSupport Compatibility"
14
+ gemspec.email = "kontakt@peritor.com"
15
+ gemspec.homepage = "http://github.com/peritor/deep_merge"
16
+ gemspec.authors = ["Steve Midgley"]
17
+ end
18
+ rescue LoadError
19
+ puts "Jeweler not available. Install it with: sudo gem install jeweler"
20
+ end
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,2 @@
1
+ require 'deep_merge/core'
2
+ require 'deep_merge/deep_merge_hash'
@@ -0,0 +1,187 @@
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
+ # :sort_merged_arrays DEFAULT: false
30
+ # Set to true to sort all arrays that are merged together
31
+ # :unpack_arrays DEFAULT: nil
32
+ # Set to string value to run "Array::join" then "String::split" against all arrays
33
+ # :merge_debug DEFAULT: false
34
+ # Set to true to get console output of merge process for debugging
35
+ #
36
+ # Selected Options Details:
37
+ # :knockout_prefix => The purpose of this is to provide a way to remove elements
38
+ # from existing Hash by specifying them in a special way in incoming hash
39
+ # source = {:x => ['--1', '2']}
40
+ # dest = {:x => ['1', '3']}
41
+ # dest.ko_deep_merge!(source)
42
+ # Results: {:x => ['2','3']}
43
+ # Additionally, if the knockout_prefix is passed alone as a string, it will cause
44
+ # the entire element to be removed:
45
+ # source = {:x => '--'}
46
+ # dest = {:x => [1,2,3]}
47
+ # dest.ko_deep_merge!(source)
48
+ # Results: {:x => ""}
49
+ # :unpack_arrays => The purpose of this is to permit compound elements to be passed
50
+ # in as strings and to be converted into discrete array elements
51
+ # irsource = {:x => ['1,2,3', '4']}
52
+ # dest = {:x => ['5','6','7,8']}
53
+ # dest.deep_merge!(source, {:unpack_arrays => ','})
54
+ # Results: {:x => ['1','2','3','4','5','6','7','8'}
55
+ # Why: If receiving data from an HTML form, this makes it easy for a checkbox
56
+ # to pass multiple values from within a single HTML element
57
+ #
58
+ # There are many tests for this library - and you can learn more about the features
59
+ # and usages of deep_merge! by just browsing the test examples
60
+ def self.deep_merge!(source, dest, options = {})
61
+ # turn on this line for stdout debugging text
62
+ merge_debug = options[:merge_debug] || false
63
+ overwrite_unmergeable = !options[:preserve_unmergeables]
64
+ knockout_prefix = options[:knockout_prefix] || nil
65
+ raise InvalidParameter, "knockout_prefix cannot be an empty string in deep_merge!" if knockout_prefix == ""
66
+ raise InvalidParameter, "overwrite_unmergeable must be true if knockout_prefix is specified in deep_merge!" if knockout_prefix && !overwrite_unmergeable
67
+ # if present: we will split and join arrays on this char before merging
68
+ array_split_char = options[:unpack_arrays] || false
69
+ # request that we sort together any arrays when they are merged
70
+ sort_merged_arrays = options[:sort_merged_arrays] || false
71
+ di = options[:debug_indent] || ''
72
+ # do nothing if source is nil
73
+ return dest if source.nil?
74
+ # if dest doesn't exist, then simply copy source to it
75
+ if !(dest) && overwrite_unmergeable
76
+ dest = source; return dest
77
+ end
78
+
79
+ puts "#{di}Source class: #{source.class.inspect} :: Dest class: #{dest.class.inspect}" if merge_debug
80
+ if source.kind_of?(Hash)
81
+ puts "#{di}Hashes: #{source.inspect} :: #{dest.inspect}" if merge_debug
82
+ source.each do |src_key, src_value|
83
+ if dest.kind_of?(Hash)
84
+ puts "#{di} looping: #{src_key.inspect} => #{src_value.inspect} :: #{dest.inspect}" if merge_debug
85
+ if dest[src_key]
86
+ puts "#{di} ==>merging: #{src_key.inspect} => #{src_value.inspect} :: #{dest[src_key].inspect}" if merge_debug
87
+ dest[src_key] = deep_merge!(src_value, dest[src_key], options.merge(:debug_indent => di + ' '))
88
+ else # dest[src_key] doesn't exist so we want to create and overwrite it (but we do this via deep_merge!)
89
+ puts "#{di} ==>merging over: #{src_key.inspect} => #{src_value.inspect}" if merge_debug
90
+ # note: we rescue here b/c some classes respond to "dup" but don't implement it (Numeric, TrueClass, FalseClass, NilClass among maybe others)
91
+ begin
92
+ src_dup = src_value.dup # we dup src_value if possible because we're going to merge into it (since dest is empty)
93
+ rescue TypeError
94
+ src_dup = src_value
95
+ end
96
+ dest[src_key] = deep_merge!(src_value, src_dup, options.merge(:debug_indent => di + ' '))
97
+ end
98
+ else # dest isn't a hash, so we overwrite it completely (if permitted)
99
+ if overwrite_unmergeable
100
+ puts "#{di} overwriting dest: #{src_key.inspect} => #{src_value.inspect} -over-> #{dest.inspect}" if merge_debug
101
+ dest = overwrite_unmergeables(source, dest, options)
102
+ end
103
+ end
104
+ end
105
+ elsif source.kind_of?(Array)
106
+ puts "#{di}Arrays: #{source.inspect} :: #{dest.inspect}" if merge_debug
107
+ # if we are instructed, join/split any source arrays before processing
108
+ if array_split_char
109
+ puts "#{di} split/join on source: #{source.inspect}" if merge_debug
110
+ source = source.join(array_split_char).split(array_split_char)
111
+ if dest.kind_of?(Array)
112
+ dest = dest.join(array_split_char).split(array_split_char)
113
+ end
114
+ end
115
+ # if there's a naked knockout_prefix in source, that means we are to truncate dest
116
+ if source.index(knockout_prefix)
117
+ dest = clear_or_nil(dest); source.delete(knockout_prefix)
118
+ end
119
+ if dest.kind_of?(Array)
120
+ if knockout_prefix
121
+ print "#{di} knocking out: " if merge_debug
122
+ # remove knockout prefix items from both source and dest
123
+ source.delete_if do |ko_item|
124
+ retval = false
125
+ item = ko_item.respond_to?(:gsub) ? ko_item.gsub(%r{^#{knockout_prefix}}, "") : ko_item
126
+ if item != ko_item
127
+ print "#{ko_item} - " if merge_debug
128
+ dest.delete(item)
129
+ dest.delete(ko_item)
130
+ retval = true
131
+ end
132
+ retval
133
+ end
134
+ puts if merge_debug
135
+ end
136
+ puts "#{di} merging arrays: #{source.inspect} :: #{dest.inspect}" if merge_debug
137
+ dest = dest | source
138
+ dest.sort! if sort_merged_arrays
139
+ elsif overwrite_unmergeable
140
+ puts "#{di} overwriting dest: #{source.inspect} -over-> #{dest.inspect}" if merge_debug
141
+ dest = overwrite_unmergeables(source, dest, options)
142
+ end
143
+ else # src_hash is not an array or hash, so we'll have to overwrite dest
144
+ puts "#{di}Others: #{source.inspect} :: #{dest.inspect}" if merge_debug
145
+ dest = overwrite_unmergeables(source, dest, options)
146
+ end
147
+ puts "#{di}Returning #{dest.inspect}" if merge_debug
148
+ dest
149
+ end # deep_merge!
150
+
151
+ # allows deep_merge! to uniformly handle overwriting of unmergeable entities
152
+ def self.overwrite_unmergeables(source, dest, options)
153
+ merge_debug = options[:merge_debug] || false
154
+ overwrite_unmergeable = !options[:preserve_unmergeables]
155
+ knockout_prefix = options[:knockout_prefix] || false
156
+ di = options[:debug_indent] || ''
157
+ if knockout_prefix && overwrite_unmergeable
158
+ if source.kind_of?(String) # remove knockout string from source before overwriting dest
159
+ src_tmp = source.gsub(%r{^#{knockout_prefix}},"")
160
+ elsif source.kind_of?(Array) # remove all knockout elements before overwriting dest
161
+ src_tmp = source.delete_if {|ko_item| ko_item.kind_of?(String) && ko_item.match(%r{^#{knockout_prefix}}) }
162
+ else
163
+ src_tmp = source
164
+ end
165
+ if src_tmp == source # if we didn't find a knockout_prefix then we just overwrite dest
166
+ puts "#{di}#{src_tmp.inspect} -over-> #{dest.inspect}" if merge_debug
167
+ dest = src_tmp
168
+ else # if we do find a knockout_prefix, then we just delete dest
169
+ puts "#{di}\"\" -over-> #{dest.inspect}" if merge_debug
170
+ dest = ""
171
+ end
172
+ elsif overwrite_unmergeable
173
+ dest = source
174
+ end
175
+ dest
176
+ end
177
+
178
+ def self.clear_or_nil(obj)
179
+ if obj.respond_to?(:clear)
180
+ obj.clear
181
+ else
182
+ obj = nil
183
+ end
184
+ obj
185
+ end
186
+
187
+ 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,572 @@
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 (sorted)
91
+ hash_src = {"property" => ["1","3"]}
92
+ hash_dst = {"property" => ["2","4"]}
93
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:sort_merged_arrays => true})
94
+ assert_equal(["1","2","3","4"].sort, hash_dst['property'])
95
+
96
+ # hashes holding hashes holding arrays (array with duplicate elements is merged with dest then src
97
+ hash_src = {"property" => {"bedroom_count" => ["1", "2"], "bathroom_count" => ["1", "4+"]}}
98
+ hash_dst = {"property" => {"bedroom_count" => ["3", "2"], "bathroom_count" => ["2"]}}
99
+ DeepMerge::deep_merge!(hash_src, hash_dst)
100
+ assert_equal({"property" => {"bedroom_count" => ["3","2","1"], "bathroom_count" => ["2", "1", "4+"]}}, hash_dst)
101
+
102
+ # hash holding hash holding array v string (string is overwritten by array)
103
+ hash_src = {"property" => {"bedroom_count" => ["1", "2"], "bathroom_count" => ["1", "4+"]}}
104
+ hash_dst = {"property" => {"bedroom_count" => "3", "bathroom_count" => ["2"]}}
105
+ DeepMerge::deep_merge!(hash_src, hash_dst)
106
+ assert_equal({"property" => {"bedroom_count" => ["1", "2"], "bathroom_count" => ["2","1","4+"]}}, hash_dst)
107
+
108
+ # hash holding hash holding array v string (string is NOT 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, {:preserve_unmergeables => true})
112
+ assert_equal({"property" => {"bedroom_count" => "3", "bathroom_count" => ["2","1","4+"]}}, hash_dst)
113
+
114
+ # hash holding hash holding string v array (array is overwritten by string)
115
+ hash_src = {"property" => {"bedroom_count" => "3", "bathroom_count" => ["1", "4+"]}}
116
+ hash_dst = {"property" => {"bedroom_count" => ["1", "2"], "bathroom_count" => ["2"]}}
117
+ DeepMerge::deep_merge!(hash_src, hash_dst)
118
+ assert_equal({"property" => {"bedroom_count" => "3", "bathroom_count" => ["2","1","4+"]}}, hash_dst)
119
+
120
+ # hash holding hash holding string v array (array does NOT overwrite 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, {:preserve_unmergeables => true})
124
+ assert_equal({"property" => {"bedroom_count" => ["1", "2"], "bathroom_count" => ["2","1","4+"]}}, hash_dst)
125
+
126
+ # hash holding hash holding hash v array (array is overwritten by hash)
127
+ hash_src = {"property" => {"bedroom_count" => {"king_bed" => 3, "queen_bed" => 1}, "bathroom_count" => ["1", "4+"]}}
128
+ hash_dst = {"property" => {"bedroom_count" => ["1", "2"], "bathroom_count" => ["2"]}}
129
+ DeepMerge::deep_merge!(hash_src, hash_dst)
130
+ assert_equal({"property" => {"bedroom_count" => {"king_bed" => 3, "queen_bed" => 1}, "bathroom_count" => ["2","1","4+"]}}, hash_dst)
131
+
132
+ # hash holding hash holding hash v array (array is NOT 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, {:preserve_unmergeables => true})
136
+ assert_equal({"property" => {"bedroom_count" => ["1", "2"], "bathroom_count" => ["2","1","4+"]}}, hash_dst)
137
+
138
+ # 3 hash layers holding integers (integers are overwritten by source)
139
+ hash_src = {"property" => {"bedroom_count" => {"king_bed" => 3, "queen_bed" => 1}, "bathroom_count" => ["1", "4+"]}}
140
+ hash_dst = {"property" => {"bedroom_count" => {"king_bed" => 2, "queen_bed" => 4}, "bathroom_count" => ["2"]}}
141
+ DeepMerge::deep_merge!(hash_src, hash_dst)
142
+ assert_equal({"property" => {"bedroom_count" => {"king_bed" => 3, "queen_bed" => 1}, "bathroom_count" => ["2","1","4+"]}}, hash_dst)
143
+
144
+ # 3 hash layers holding arrays of int (arrays are merged)
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" => [2,3], "queen_bed" => [4,1]}, "bathroom_count" => ["2","1","4+"]}}, hash_dst)
149
+
150
+ # 1 hash overwriting 3 hash layers holding arrays of int
151
+ hash_src = {"property" => "1"}
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" => "1"}, hash_dst)
155
+
156
+ # 1 hash NOT 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, {:preserve_unmergeables => true})
160
+ assert_equal({"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}, hash_dst)
161
+
162
+ # 3 hash layers holding arrays of int (arrays are merged) but second hash's array is overwritten
163
+ hash_src = {"property" => {"bedroom_count" => {"king_bed" => [3], "queen_bed" => [1]}, "bathroom_count" => "1"}}
164
+ hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
165
+ DeepMerge::deep_merge!(hash_src, hash_dst)
166
+ assert_equal({"property" => {"bedroom_count" => {"king_bed" => [2,3], "queen_bed" => [4,1]}, "bathroom_count" => "1"}}, hash_dst)
167
+
168
+ # 3 hash layers holding arrays of int (arrays are merged) but second hash's array is NOT 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, {:preserve_unmergeables => true})
172
+ assert_equal({"property" => {"bedroom_count" => {"king_bed" => [2,3], "queen_bed" => [4,1]}, "bathroom_count" => ["2"]}}, hash_dst)
173
+
174
+ # 3 hash layers holding arrays of int, but one holds int. This one overwrites, but the rest merge
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)
178
+ assert_equal({"property" => {"bedroom_count" => {"king_bed" => 3, "queen_bed" => [4,1]}, "bathroom_count" => ["2","1"]}}, hash_dst)
179
+
180
+ # 3 hash layers holding arrays of int, but source is incomplete.
181
+ hash_src = {"property" => {"bedroom_count" => {"king_bed" => [3]}, "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" => [2,3], "queen_bed" => [4]}, "bathroom_count" => ["2","1"]}}, hash_dst)
185
+
186
+ # 3 hash layers holding arrays of int, but source is shorter and has new 2nd level ints.
187
+ hash_src = {"property" => {"bedroom_count" => {2=>3, "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" => {2=>3, "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 empty
193
+ hash_src = {}
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" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}, hash_dst)
197
+
198
+ # 3 hash layers holding arrays of int, but dest is empty
199
+ hash_src = {"property" => {"bedroom_count" => {2=>3, "king_bed" => [3]}, "bathroom_count" => ["1"]}}
200
+ hash_dst = {}
201
+ DeepMerge::deep_merge!(hash_src, hash_dst)
202
+ assert_equal({"property" => {"bedroom_count" => {2=>3, "king_bed" => [3]}, "bathroom_count" => ["1"]}}, hash_dst)
203
+
204
+ # test parameter management for knockout_prefix and overwrite unmergable
205
+ assert_raise(DeepMerge::InvalidParameter) {DeepMerge::deep_merge!(hash_src, hash_dst, {:knockout_prefix => ""})}
206
+ assert_raise(DeepMerge::InvalidParameter) {DeepMerge::deep_merge!(hash_src, hash_dst, {:preserve_unmergeables => true, :knockout_prefix => ""})}
207
+ assert_raise(DeepMerge::InvalidParameter) {DeepMerge::deep_merge!(hash_src, hash_dst, {:preserve_unmergeables => true, :knockout_prefix => "--"})}
208
+ assert_nothing_raised(DeepMerge::InvalidParameter) {DeepMerge::deep_merge!(hash_src, hash_dst, {:knockout_prefix => "--"})}
209
+ assert_nothing_raised(DeepMerge::InvalidParameter) {DeepMerge::deep_merge!(hash_src, hash_dst)}
210
+ assert_nothing_raised(DeepMerge::InvalidParameter) {DeepMerge::deep_merge!(hash_src, hash_dst, {:preserve_unmergeables => true})}
211
+
212
+ # hash holding arrays of arrays
213
+ hash_src = {["1", "2", "3"] => ["1", "2"]}
214
+ hash_dst = {["4", "5"] => ["3"]}
215
+ DeepMerge::deep_merge!(hash_src, hash_dst)
216
+ assert_equal({["1","2","3"] => ["1", "2"], ["4", "5"] => ["3"]}, hash_dst)
217
+
218
+ # test merging of hash with blank hash, and make sure that source array split still functions
219
+ hash_src = {'property' => {'bedroom_count' => ["1","2,3"]}}
220
+ hash_dst = {}
221
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ","})
222
+ assert_equal({'property' => {'bedroom_count' => ["1","2","3"]}}, hash_dst)
223
+
224
+ # test merging of hash with blank hash, and make sure that source array split does not function when turned off
225
+ hash_src = {'property' => {'bedroom_count' => ["1","2,3"]}}
226
+ hash_dst = {}
227
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX})
228
+ assert_equal({'property' => {'bedroom_count' => ["1","2,3"]}}, hash_dst)
229
+
230
+ # test merging into a blank hash with overwrite_unmergeables turned on
231
+ hash_src = {"action"=>"browse", "controller"=>"results"}
232
+ hash_dst = {}
233
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:overwrite_unmergeables => true, :knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ","})
234
+ assert_equal hash_src, hash_dst
235
+
236
+ # KNOCKOUT_PREFIX testing
237
+ # the next few tests are looking for correct behavior from specific real-world params/session merges
238
+ # using the custom modifiers built for param/session merges
239
+
240
+ [nil, ","].each do |ko_split|
241
+ # typical params/session style hash with knockout_merge elements
242
+ hash_params = {"property"=>{"bedroom_count"=>[FIELD_KNOCKOUT_PREFIX+"1", "2", "3"]}}
243
+ hash_session = {"property"=>{"bedroom_count"=>["1", "2", "3"]}}
244
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ko_split})
245
+ assert_equal({"property"=>{"bedroom_count"=>["2", "3"]}}, hash_session)
246
+
247
+ # typical params/session style hash with knockout_merge elements
248
+ hash_params = {"property"=>{"bedroom_count"=>[FIELD_KNOCKOUT_PREFIX+"1", "2", "3"]}}
249
+ hash_session = {"property"=>{"bedroom_count"=>["3"]}}
250
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ko_split})
251
+ assert_equal({"property"=>{"bedroom_count"=>["3","2"]}}, hash_session)
252
+
253
+ # typical params/session style hash with knockout_merge elements
254
+ hash_params = {"property"=>{"bedroom_count"=>[FIELD_KNOCKOUT_PREFIX+"1", "2", "3"]}}
255
+ hash_session = {"property"=>{"bedroom_count"=>["4"]}}
256
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ko_split})
257
+ assert_equal({"property"=>{"bedroom_count"=>["4","2","3"]}}, hash_session)
258
+
259
+ # typical params/session style hash with knockout_merge elements
260
+ hash_params = {"property"=>{"bedroom_count"=>[FIELD_KNOCKOUT_PREFIX+"1", "2", "3"]}}
261
+ hash_session = {"property"=>{"bedroom_count"=>[FIELD_KNOCKOUT_PREFIX+"1", "4"]}}
262
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ko_split})
263
+ assert_equal({"property"=>{"bedroom_count"=>["4","2","3"]}}, hash_session)
264
+
265
+ # typical params/session style hash with knockout_merge elements
266
+ hash_params = {"amenity"=>{"id"=>[FIELD_KNOCKOUT_PREFIX+"1", FIELD_KNOCKOUT_PREFIX+"2", "3", "4"]}}
267
+ hash_session = {"amenity"=>{"id"=>["1", "2"]}}
268
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ko_split})
269
+ assert_equal({"amenity"=>{"id"=>["3","4"]}}, hash_session)
270
+ end
271
+
272
+ # special params/session style hash with knockout_merge elements in form src: ["1","2"] dest:["--1,--2", "3,4"]
273
+ hash_params = {"amenity"=>{"id"=>[FIELD_KNOCKOUT_PREFIX+"1,"+FIELD_KNOCKOUT_PREFIX+"2", "3,4"]}}
274
+ hash_session = {"amenity"=>{"id"=>["1", "2"]}}
275
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ","})
276
+ assert_equal({"amenity"=>{"id"=>["3","4"]}}, hash_session)
277
+
278
+ # same as previous but without ko_split value, this merge should fail
279
+ hash_params = {"amenity"=>{"id"=>[FIELD_KNOCKOUT_PREFIX+"1,"+FIELD_KNOCKOUT_PREFIX+"2", "3,4"]}}
280
+ hash_session = {"amenity"=>{"id"=>["1", "2"]}}
281
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX})
282
+ assert_equal({"amenity"=>{"id"=>["1","2","3,4"]}}, hash_session)
283
+
284
+ # special params/session style hash with knockout_merge elements in form src: ["1","2"] dest:["--1,--2", "3,4"]
285
+ hash_params = {"amenity"=>{"id"=>[FIELD_KNOCKOUT_PREFIX+"1,2", "3,4", "--5", "6"]}}
286
+ hash_session = {"amenity"=>{"id"=>["1", "2"]}}
287
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ","})
288
+ assert_equal({"amenity"=>{"id"=>["2","3","4","6"]}}, hash_session)
289
+
290
+ # special params/session style hash with knockout_merge elements in form src: ["--1,--2", "3,4", "--5", "6"] dest:["1,2", "3,4"]
291
+ hash_params = {"amenity"=>{"id"=>["#{FIELD_KNOCKOUT_PREFIX}1,#{FIELD_KNOCKOUT_PREFIX}2", "3,4", "#{FIELD_KNOCKOUT_PREFIX}5", "6"]}}
292
+ hash_session = {"amenity"=>{"id"=>["1", "2", "3", "4"]}}
293
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ","})
294
+ assert_equal({"amenity"=>{"id"=>["3","4","6"]}}, hash_session)
295
+
296
+
297
+ hash_src = {"url_regions"=>[], "region"=>{"ids"=>["227,233"]}, "action"=>"browse", "task"=>"browse", "controller"=>"results"}
298
+ hash_dst = {"region"=>{"ids"=>["227"]}}
299
+ DeepMerge::deep_merge!(hash_src.dup, hash_dst, {:overwrite_unmergeables => true, :knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ","})
300
+ assert_equal({"url_regions"=>[], "region"=>{"ids"=>["227","233"]}, "action"=>"browse", "task"=>"browse", "controller"=>"results"}, hash_dst)
301
+
302
+ hash_src = {"region"=>{"ids"=>["--","227"], "id"=>"230"}}
303
+ hash_dst = {"region"=>{"ids"=>["227", "233", "324", "230", "230"], "id"=>"230"}}
304
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:overwrite_unmergeables => true, :knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ","})
305
+ assert_equal({"region"=>{"ids"=>["227"], "id"=>"230"}}, hash_dst)
306
+
307
+ hash_src = {"region"=>{"ids"=>["--","227", "232", "233"], "id"=>"232"}}
308
+ hash_dst = {"region"=>{"ids"=>["227", "233", "324", "230", "230"], "id"=>"230"}}
309
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:overwrite_unmergeables => true, :knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ","})
310
+ assert_equal({"region"=>{"ids"=>["227", "232", "233"], "id"=>"232"}}, hash_dst)
311
+
312
+ hash_src = {"region"=>{"ids"=>["--,227,232,233"], "id"=>"232"}}
313
+ hash_dst = {"region"=>{"ids"=>["227", "233", "324", "230", "230"], "id"=>"230"}}
314
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:overwrite_unmergeables => true, :knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ","})
315
+ assert_equal({"region"=>{"ids"=>["227", "232", "233"], "id"=>"232"}}, hash_dst)
316
+
317
+ hash_src = {"region"=>{"ids"=>["--,227,232","233"], "id"=>"232"}}
318
+ hash_dst = {"region"=>{"ids"=>["227", "233", "324", "230", "230"], "id"=>"230"}}
319
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:overwrite_unmergeables => true, :knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ","})
320
+ assert_equal({"region"=>{"ids"=>["227", "232", "233"], "id"=>"232"}}, hash_dst)
321
+
322
+ hash_src = {"region"=>{"ids"=>["--,227"], "id"=>"230"}}
323
+ hash_dst = {"region"=>{"ids"=>["227", "233", "324", "230", "230"], "id"=>"230"}}
324
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:overwrite_unmergeables => true, :knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ","})
325
+ assert_equal({"region"=>{"ids"=>["227"], "id"=>"230"}}, hash_dst)
326
+
327
+ hash_src = {"region"=>{"ids"=>["--,227"], "id"=>"230"}}
328
+ hash_dst = {"region"=>{"ids"=>["227", "233", "324", "230", "230"], "id"=>"230"}, "action"=>"browse", "task"=>"browse", "controller"=>"results", "property_order_by"=>"property_type.descr"}
329
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:overwrite_unmergeables => true, :knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ","})
330
+ assert_equal({"region"=>{"ids"=>["227"], "id"=>"230"}, "action"=>"browse", "task"=>"browse",
331
+ "controller"=>"results", "property_order_by"=>"property_type.descr"}, hash_dst)
332
+
333
+ hash_src = {"query_uuid"=>"6386333d-389b-ab5c-8943-6f3a2aa914d7", "region"=>{"ids"=>["--,227"], "id"=>"230"}}
334
+ 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"}
335
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:overwrite_unmergeables => true, :knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ","})
336
+ assert_equal({"query_uuid" => "6386333d-389b-ab5c-8943-6f3a2aa914d7", "url_regions"=>[],
337
+ "region"=>{"ids"=>["227"], "id"=>"230"}, "action"=>"browse", "task"=>"browse",
338
+ "controller"=>"results", "property_order_by"=>"property_type.descr"}, hash_dst)
339
+
340
+ # knock out entire dest hash if "--" is passed for source
341
+ hash_params = {'amenity' => "--"}
342
+ hash_session = {"amenity" => "1"}
343
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => "--", :unpack_arrays => ","})
344
+ assert_equal({'amenity' => ""}, hash_session)
345
+
346
+ # knock out entire dest hash if "--" is passed for source
347
+ hash_params = {'amenity' => ["--"]}
348
+ hash_session = {"amenity" => "1"}
349
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => "--", :unpack_arrays => ","})
350
+ assert_equal({'amenity' => []}, hash_session)
351
+
352
+ # knock out entire dest hash if "--" is passed for source
353
+ hash_params = {'amenity' => "--"}
354
+ hash_session = {"amenity" => ["1"]}
355
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => "--", :unpack_arrays => ","})
356
+ assert_equal({'amenity' => ""}, hash_session)
357
+
358
+ # knock out entire dest hash if "--" is passed for source
359
+ hash_params = {'amenity' => ["--"]}
360
+ hash_session = {"amenity" => ["1"]}
361
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => "--", :unpack_arrays => ","})
362
+ assert_equal({'amenity' => []}, hash_session)
363
+
364
+ # knock out entire dest hash if "--" is passed for source
365
+ hash_params = {'amenity' => ["--"]}
366
+ hash_session = {"amenity" => "1"}
367
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => "--", :unpack_arrays => ","})
368
+ assert_equal({'amenity' => []}, hash_session)
369
+
370
+ # knock out entire dest hash if "--" is passed for source
371
+ hash_params = {'amenity' => ["--", "2"]}
372
+ hash_session = {'amenity' => ["1", "3", "7+"]}
373
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => "--", :unpack_arrays => ","})
374
+ assert_equal({'amenity' => ["2"]}, hash_session)
375
+
376
+ # knock out entire dest hash if "--" is passed for source
377
+ hash_params = {'amenity' => ["--", "2"]}
378
+ hash_session = {'amenity' => "5"}
379
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => "--", :unpack_arrays => ","})
380
+ assert_equal({'amenity' => ['2']}, hash_session)
381
+
382
+ # knock out entire dest hash if "--" is passed for source
383
+ hash_params = {'amenity' => "--"}
384
+ hash_session = {"amenity"=>{"id"=>["1", "2", "3", "4"]}}
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"=>{"id"=>["1", "2", "3", "4"]}}
391
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => "--", :unpack_arrays => ","})
392
+ assert_equal({'amenity' => []}, hash_session)
393
+
394
+ # knock out dest array if "--" is passed for source
395
+ hash_params = {"region" => {'ids' => FIELD_KNOCKOUT_PREFIX}}
396
+ hash_session = {"region"=>{"ids"=>["1", "2", "3", "4"]}}
397
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ","})
398
+ assert_equal({'region' => {'ids' => ""}}, hash_session)
399
+
400
+ # knock out dest array but leave other elements of hash intact
401
+ hash_params = {"region" => {'ids' => FIELD_KNOCKOUT_PREFIX}}
402
+ hash_session = {"region"=>{"ids"=>["1", "2", "3", "4"], 'id'=>'11'}}
403
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ","})
404
+ assert_equal({'region' => {'ids' => "", 'id'=>'11'}}, hash_session)
405
+
406
+ # knock out entire tree of dest hash
407
+ hash_params = {"region" => FIELD_KNOCKOUT_PREFIX}
408
+ hash_session = {"region"=>{"ids"=>["1", "2", "3", "4"], 'id'=>'11'}}
409
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ","})
410
+ assert_equal({'region' => ""}, hash_session)
411
+
412
+ # knock out entire tree of dest hash - retaining array format
413
+ hash_params = {"region" => {'ids' => [FIELD_KNOCKOUT_PREFIX]}}
414
+ hash_session = {"region"=>{"ids"=>["1", "2", "3", "4"], 'id'=>'11'}}
415
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ","})
416
+ assert_equal({'region' => {'ids' => [], 'id'=>'11'}}, hash_session)
417
+
418
+ # knock out entire tree of dest hash & replace with new content
419
+ hash_params = {"region" => {'ids' => ["2", FIELD_KNOCKOUT_PREFIX, "6"]}}
420
+ hash_session = {"region"=>{"ids"=>["1", "2", "3", "4"], 'id'=>'11'}}
421
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ","})
422
+ assert_equal({'region' => {'ids' => ["2", "6"], 'id'=>'11'}}, hash_session)
423
+
424
+ # knock out entire tree of dest hash & replace with new content
425
+ hash_params = {"region" => {'ids' => ["7", FIELD_KNOCKOUT_PREFIX, "6"]}}
426
+ hash_session = {"region"=>{"ids"=>["1", "2", "3", "4"], 'id'=>'11'}}
427
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ","})
428
+ assert_equal({'region' => {'ids' => ["7", "6"], 'id'=>'11'}}, hash_session)
429
+
430
+ # edge test: make sure that when we turn off knockout_prefix that all values are processed correctly
431
+ hash_params = {"region" => {'ids' => ["7", "--", "2", "6,8"]}}
432
+ hash_session = {"region"=>{"ids"=>["1", "2", "3", "4"], 'id'=>'11'}}
433
+ DeepMerge::deep_merge!(hash_params, hash_session, {:unpack_arrays => ","})
434
+ assert_equal({'region' => {'ids' => ["1", "2", "3", "4", "7", "--", "6", "8"], 'id'=>'11'}}, hash_session)
435
+
436
+ # edge test 2: make sure that when we turn off source array split that all values are processed correctly
437
+ hash_params = {"region" => {'ids' => ["7", "3", "--", "6,8"]}}
438
+ hash_session = {"region"=>{"ids"=>["1", "2", "3", "4"], 'id'=>'11'}}
439
+ DeepMerge::deep_merge!(hash_params, hash_session)
440
+ assert_equal({'region' => {'ids' => ["1", "2", "3", "4", "7", "--", "6,8"], 'id'=>'11'}}, hash_session)
441
+
442
+ # Example: src = {'key' => "--1"}, dst = {'key' => "1"} -> merges to {'key' => ""}
443
+ hash_params = {"amenity"=>"--1"}
444
+ hash_session = {"amenity"=>"1"}
445
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX})
446
+ assert_equal({"amenity"=>""}, hash_session)
447
+
448
+ # Example: src = {'key' => "--1"}, dst = {'key' => "2"} -> merges to {'key' => ""}
449
+ hash_params = {"amenity"=>"--1"}
450
+ hash_session = {"amenity"=>"2"}
451
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX})
452
+ assert_equal({"amenity"=>""}, hash_session)
453
+
454
+ # Example: src = {'key' => "--1"}, dst = {'key' => "1"} -> merges to {'key' => ""}
455
+ hash_params = {"amenity"=>["--1"]}
456
+ hash_session = {"amenity"=>"1"}
457
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX})
458
+ assert_equal({"amenity"=>[]}, hash_session)
459
+
460
+ # Example: src = {'key' => "--1"}, dst = {'key' => "1"} -> merges to {'key' => ""}
461
+ hash_params = {"amenity"=>["--1"]}
462
+ hash_session = {"amenity"=>["1"]}
463
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX})
464
+ assert_equal({"amenity"=>[]}, hash_session)
465
+
466
+ # Example: src = {'key' => "--1"}, dst = {'key' => "1"} -> merges to {'key' => ""}
467
+ hash_params = {"amenity"=>"--1"}
468
+ hash_session = {}
469
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX})
470
+ assert_equal({"amenity"=>""}, hash_session)
471
+
472
+
473
+ # Example: src = {'key' => "--1"}, dst = {'key' => "1"} -> merges to {'key' => ""}
474
+ hash_params = {"amenity"=>"--1"}
475
+ hash_session = {"amenity"=>["1"]}
476
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX})
477
+ assert_equal({"amenity"=>""}, hash_session)
478
+
479
+ #are unmerged hashes passed unmodified w/out :unpack_arrays?
480
+ hash_params = {"amenity"=>{"id"=>["26,27"]}}
481
+ hash_session = {}
482
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX})
483
+ assert_equal({"amenity"=>{"id"=>["26,27"]}}, hash_session)
484
+
485
+ #hash should be merged
486
+ hash_params = {"amenity"=>{"id"=>["26,27"]}}
487
+ hash_session = {}
488
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ","})
489
+ assert_equal({"amenity"=>{"id"=>["26","27"]}}, hash_session)
490
+
491
+ # second merge of same values should result in no change in output
492
+ hash_params = {"amenity"=>{"id"=>["26,27"]}}
493
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ","})
494
+ assert_equal({"amenity"=>{"id"=>["26","27"]}}, hash_session)
495
+
496
+ #hashes with knockout values are suppressed
497
+ hash_params = {"amenity"=>{"id"=>["#{FIELD_KNOCKOUT_PREFIX}26,#{FIELD_KNOCKOUT_PREFIX}27,28"]}}
498
+ hash_session = {}
499
+ DeepMerge::deep_merge!(hash_params, hash_session, {:knockout_prefix => FIELD_KNOCKOUT_PREFIX, :unpack_arrays => ","})
500
+ assert_equal({"amenity"=>{"id"=>["28"]}}, hash_session)
501
+
502
+ hash_src= {'region' =>{'ids'=>['--']}, 'query_uuid' => 'zzz'}
503
+ hash_dst= {'region' =>{'ids'=>['227','2','3','3']}, 'query_uuid' => 'zzz'}
504
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:knockout_prefix => '--', :unpack_arrays => ","})
505
+ assert_equal({'region' =>{'ids'=>[]}, 'query_uuid' => 'zzz'}, hash_dst)
506
+
507
+ hash_src= {'region' =>{'ids'=>['--']}, 'query_uuid' => 'zzz'}
508
+ hash_dst= {'region' =>{'ids'=>['227','2','3','3'], 'id' => '3'}, 'query_uuid' => 'zzz'}
509
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:knockout_prefix => '--', :unpack_arrays => ","})
510
+ assert_equal({'region' =>{'ids'=>[], 'id'=>'3'}, 'query_uuid' => 'zzz'}, hash_dst)
511
+
512
+ hash_src= {'region' =>{'ids'=>['--']}, 'query_uuid' => 'zzz'}
513
+ hash_dst= {'region' =>{'muni_city_id' => '2244', 'ids'=>['227','2','3','3'], 'id'=>'3'}, 'query_uuid' => 'zzz'}
514
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:knockout_prefix => '--', :unpack_arrays => ","})
515
+ assert_equal({'region' =>{'muni_city_id' => '2244', 'ids'=>[], 'id'=>'3'}, 'query_uuid' => 'zzz'}, hash_dst)
516
+
517
+ hash_src= {'region' =>{'ids'=>['--'], 'id' => '5'}, 'query_uuid' => 'zzz'}
518
+ hash_dst= {'region' =>{'muni_city_id' => '2244', 'ids'=>['227','2','3','3'], 'id'=>'3'}, 'query_uuid' => 'zzz'}
519
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:knockout_prefix => '--', :unpack_arrays => ","})
520
+ assert_equal({'region' =>{'muni_city_id' => '2244', 'ids'=>[], 'id'=>'5'}, 'query_uuid' => 'zzz'}, hash_dst)
521
+
522
+ hash_src= {'region' =>{'ids'=>['--', '227'], 'id' => '5'}, 'query_uuid' => 'zzz'}
523
+ hash_dst= {'region' =>{'muni_city_id' => '2244', 'ids'=>['227','2','3','3'], 'id'=>'3'}, 'query_uuid' => 'zzz'}
524
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:knockout_prefix => '--', :unpack_arrays => ","})
525
+ assert_equal({'region' =>{'muni_city_id' => '2244', 'ids'=>['227'], 'id'=>'5'}, 'query_uuid' => 'zzz'}, hash_dst)
526
+
527
+ hash_src= {'region' =>{'muni_city_id' => '--', 'ids'=>'--', 'id'=>'5'}, 'query_uuid' => 'zzz'}
528
+ hash_dst= {'region' =>{'muni_city_id' => '2244', 'ids'=>['227','2','3','3'], 'id'=>'3'}, 'query_uuid' => 'zzz'}
529
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:knockout_prefix => '--', :unpack_arrays => ","})
530
+ assert_equal({'region' =>{'muni_city_id' => '', 'ids'=>'', 'id'=>'5'}, 'query_uuid' => 'zzz'}, hash_dst)
531
+
532
+ hash_src= {'region' =>{'muni_city_id' => '--', 'ids'=>['--'], 'id'=>'5'}, 'query_uuid' => 'zzz'}
533
+ hash_dst= {'region' =>{'muni_city_id' => '2244', 'ids'=>['227','2','3','3'], 'id'=>'3'}, 'query_uuid' => 'zzz'}
534
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:knockout_prefix => '--', :unpack_arrays => ","})
535
+ assert_equal({'region' =>{'muni_city_id' => '', 'ids'=>[], 'id'=>'5'}, 'query_uuid' => 'zzz'}, hash_dst)
536
+
537
+ hash_src= {'region' =>{'muni_city_id' => '--', 'ids'=>['--','227'], 'id'=>'5'}, 'query_uuid' => 'zzz'}
538
+ hash_dst= {'region' =>{'muni_city_id' => '2244', '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' =>{'muni_city_id' => '', 'ids'=>['227'], 'id'=>'5'}, 'query_uuid' => 'zzz'}, hash_dst)
541
+
542
+ hash_src = {"muni_city_id"=>"--", "id"=>""}
543
+ hash_dst = {"muni_city_id"=>"", "id"=>""}
544
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:knockout_prefix => '--', :unpack_arrays => ","})
545
+ assert_equal({"muni_city_id"=>"", "id"=>""}, hash_dst)
546
+
547
+ hash_src = {"region"=>{"muni_city_id"=>"--", "id"=>""}}
548
+ hash_dst = {"region"=>{"muni_city_id"=>"", "id"=>""}}
549
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:knockout_prefix => '--', :unpack_arrays => ","})
550
+ assert_equal({"region"=>{"muni_city_id"=>"", "id"=>""}}, hash_dst)
551
+
552
+ 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"}
553
+ 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"}
554
+ DeepMerge::deep_merge!(hash_src, hash_dst, {:knockout_prefix => '--', :unpack_arrays => ","})
555
+ 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)
556
+
557
+ # hash of array of hashes
558
+ hash_src = {"item" => [{"1" => "3"}, {"2" => "4"}]}
559
+ hash_dst = {"item" => [{"3" => "5"}]}
560
+ DeepMerge::deep_merge!(hash_src, hash_dst)
561
+ assert_equal({"item" => [{"3" => "5"}, {"1" => "3"}, {"2" => "4"}]}, hash_dst)
562
+
563
+
564
+ # Merging empty strings
565
+ s1, s2 = "hello", ""
566
+ [s1, s2].each { |s| s.extend StringBlank }
567
+ hash_dst = {"item" => s1 }
568
+ hash_src = {"item" => s2 }
569
+ DeepMerge::deep_merge!(hash_src, hash_dst)
570
+ assert_equal({"item" => ""}, hash_dst)
571
+ end # test_deep_merge
572
+ end