hashdiff 0.3.9 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1de380f239260b12890d36de1548ee8a9159a15d
4
- data.tar.gz: be13f7000b31ac211e59c8e5c924a976a39fb26c
3
+ metadata.gz: 204c04301ec7d5b755863a0ec7b9001930a569c1
4
+ data.tar.gz: c0bf2c27e34271b637da82792549104a5b0ca2cb
5
5
  SHA512:
6
- metadata.gz: bad33e3fd08a4f7b14388f54c17060153a48832eda6c06e6d137ce23b901cd14183630eabcfa7e1da6d2c93f33d7b59109a7fee0e78a23f2a3102e3576c35846
7
- data.tar.gz: 7fa406149636c91d9cc5abc49b926f92e8b4962654e9b78ef18b3938dc971ce2f51cf16b2c01b3968556cc20fbfb577437b76a7094ecf0ba4eb5cd00cdba0bb3
6
+ metadata.gz: 68f07faf7b58132dae314317cf90e1dae5549218d93c19be33df0460659d2e74a861f458c9f6401909ce78ca1b0cb649cc843e0a804a4dad70e3c824568bfd7c
7
+ data.tar.gz: ba2ff10babe7886c263cbac1c761a38e205880dc323199746ed6845762b462a08b7664f9f1159b5765751b020dfd38ac365fcec04e350d894f97df6b519f3c71
@@ -1,5 +1,6 @@
1
1
  sudo: false
2
2
  language: ruby
3
+ cache: bundler
3
4
  rvm:
4
5
  - 2.0.0
5
6
  - 2.1.10
data/README.md CHANGED
@@ -1,17 +1,17 @@
1
- # HashDiff [![Build Status](https://secure.travis-ci.org/liufengyun/hashdiff.svg)](http://travis-ci.org/liufengyun/hashdiff) [![Gem Version](https://badge.fury.io/rb/hashdiff.svg)](http://badge.fury.io/rb/hashdiff)
1
+ # Hashdiff [![Build Status](https://secure.travis-ci.org/liufengyun/hashdiff.svg)](http://travis-ci.org/liufengyun/hashdiff) [![Gem Version](https://badge.fury.io/rb/hashdiff.svg)](http://badge.fury.io/rb/hashdiff)
2
2
 
3
- HashDiff is a ruby library to compute the smallest difference between two hashes.
3
+ Hashdiff is a ruby library to compute the smallest difference between two hashes.
4
4
 
5
5
  It also supports comparing two arrays.
6
6
 
7
- HashDiff does not monkey-patch any existing class. All features are contained inside the `HashDiff` module.
7
+ Hashdiff does not monkey-patch any existing class. All features are contained inside the `Hashdiff` module.
8
8
 
9
9
  **Docs**: [Documentation](http://rubydoc.info/gems/hashdiff)
10
10
 
11
11
 
12
12
  __WARNING__: Don't use the library for comparing large arrays, say ~10K (see #49).
13
13
 
14
- ## Why HashDiff?
14
+ ## Why Hashdiff?
15
15
 
16
16
  Given two Hashes A and B, sometimes you face the question: what's the smallest modification that can be made to change A into B?
17
17
 
@@ -21,7 +21,7 @@ An algorithm that responds to this question has to do following:
21
21
  * Compute recursively -- Arrays and Hashes may be nested arbitrarily in A or B.
22
22
  * Compute the smallest change -- it should recognize similar child Hashes or child Arrays between A and B.
23
23
 
24
- HashDiff answers the question above using an opinionated approach:
24
+ Hashdiff answers the question above using an opinionated approach:
25
25
 
26
26
  * Hash can be represented as a list of (dot-syntax-path, value) pairs. For example, `{a:[{c:2}]}` can be represented as `["a[0].c", 2]`.
27
27
  * The change set can be represented using the dot-syntax representation. For example, `[['-', 'b.x', 3], ['~', 'b.z', 45, 30], ['+', 'b.y', 3]]`.
@@ -46,7 +46,7 @@ Two simple hashes:
46
46
  a = {a:3, b:2}
47
47
  b = {}
48
48
 
49
- diff = HashDiff.diff(a, b)
49
+ diff = Hashdiff.diff(a, b)
50
50
  diff.should == [['-', 'a', 3], ['-', 'b', 2]]
51
51
  ```
52
52
 
@@ -56,7 +56,7 @@ More complex hashes:
56
56
  a = {a:{x:2, y:3, z:4}, b:{x:3, z:45}}
57
57
  b = {a:{y:3}, b:{y:3, z:30}}
58
58
 
59
- diff = HashDiff.diff(a, b)
59
+ diff = Hashdiff.diff(a, b)
60
60
  diff.should == [['-', 'a.x', 2], ['-', 'a.z', 4], ['-', 'b.x', 3], ['~', 'b.z', 45, 30], ['+', 'b.y', 3]]
61
61
  ```
62
62
 
@@ -66,7 +66,7 @@ Arrays in hashes:
66
66
  a = {a:[{x:2, y:3, z:4}, {x:11, y:22, z:33}], b:{x:3, z:45}}
67
67
  b = {a:[{y:3}, {x:11, z:33}], b:{y:22}}
68
68
 
69
- diff = HashDiff.best_diff(a, b)
69
+ diff = Hashdiff.best_diff(a, b)
70
70
  diff.should == [['-', 'a[0].x', 2], ['-', 'a[0].z', 4], ['-', 'a[1].y', 22], ['-', 'b.x', 3], ['-', 'b.z', 45], ['+', 'b.y', 22]]
71
71
  ```
72
72
 
@@ -78,8 +78,8 @@ patch example:
78
78
  a = {'a' => 3}
79
79
  b = {'a' => {'a1' => 1, 'a2' => 2}}
80
80
 
81
- diff = HashDiff.diff(a, b)
82
- HashDiff.patch!(a, diff).should == b
81
+ diff = Hashdiff.diff(a, b)
82
+ Hashdiff.patch!(a, diff).should == b
83
83
  ```
84
84
 
85
85
  unpatch example:
@@ -88,8 +88,8 @@ unpatch example:
88
88
  a = [{'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5}, {'x' => 5, 'y' => 6, 'z' => 3}, 1]
89
89
  b = [1, {'a' => 1, 'b' => 2, 'c' => 3, 'e' => 5}]
90
90
 
91
- diff = HashDiff.diff(a, b) # diff two array is OK
92
- HashDiff.unpatch!(b, diff).should == a
91
+ diff = Hashdiff.diff(a, b) # diff two array is OK
92
+ Hashdiff.unpatch!(b, diff).should == a
93
93
  ```
94
94
 
95
95
  ### Options
@@ -106,7 +106,7 @@ You can specify `:delimiter` to be something other than the default dot. For exa
106
106
  a = {a:{x:2, y:3, z:4}, b:{x:3, z:45}}
107
107
  b = {a:{y:3}, b:{y:3, z:30}}
108
108
 
109
- diff = HashDiff.diff(a, b, :delimiter => '\t')
109
+ diff = Hashdiff.diff(a, b, :delimiter => '\t')
110
110
  diff.should == [['-', 'a\tx', 2], ['-', 'a\tz', 4], ['-', 'b\tx', 3], ['~', 'b\tz', 45, 30], ['+', 'b\ty', 3]]
111
111
  ```
112
112
 
@@ -126,7 +126,7 @@ The :numeric_tolerance option allows for a small numeric tolerance.
126
126
  a = {x:5, y:3.75, z:7}
127
127
  b = {x:6, y:3.76, z:7}
128
128
 
129
- diff = HashDiff.diff(a, b, :numeric_tolerance => 0.1)
129
+ diff = Hashdiff.diff(a, b, :numeric_tolerance => 0.1)
130
130
  diff.should == [["~", "x", 5, 6]]
131
131
  ```
132
132
 
@@ -138,7 +138,7 @@ The :strip option strips all strings before comparing.
138
138
  a = {x:5, s:'foo '}
139
139
  b = {x:6, s:'foo'}
140
140
 
141
- diff = HashDiff.diff(a, b, :comparison => { :numeric_tolerance => 0.1, :strip => true })
141
+ diff = Hashdiff.diff(a, b, :comparison => { :numeric_tolerance => 0.1, :strip => true })
142
142
  diff.should == [["~", "x", 5, 6]]
143
143
  ```
144
144
 
@@ -150,7 +150,7 @@ The :case_insensitive option makes string comparisons ignore case.
150
150
  a = {x:5, s:'FooBar'}
151
151
  b = {x:6, s:'foobar'}
152
152
 
153
- diff = HashDiff.diff(a, b, :comparison => { :numeric_tolerance => 0.1, :case_insensitive => true })
153
+ diff = Hashdiff.diff(a, b, :comparison => { :numeric_tolerance => 0.1, :case_insensitive => true })
154
154
  diff.should == [["~", "x", 5, 6]]
155
155
  ```
156
156
 
@@ -164,7 +164,7 @@ is useful for `patch!` when used on hashes without string keys.
164
164
  a = {x:5}
165
165
  b = {'x'=>6}
166
166
 
167
- diff = HashDiff.diff(a, b, :array_path => true)
167
+ diff = Hashdiff.diff(a, b, :array_path => true)
168
168
  diff.should == [['-', [:x], 5], ['+', ['x'], 6]]
169
169
  ```
170
170
 
@@ -173,7 +173,7 @@ For cases where there are arrays in paths their index will be added to the path.
173
173
  a = {x:[0,1]}
174
174
  b = {x:[0,2]}
175
175
 
176
- diff = HashDiff.diff(a, b, :array_path => true)
176
+ diff = Hashdiff.diff(a, b, :array_path => true)
177
177
  diff.should == [["-", [:x, 1], 1], ["+", [:x, 1], 2]]
178
178
  ```
179
179
 
@@ -183,8 +183,8 @@ This shouldn't cause problems if you are comparing an array with a hash:
183
183
  a = {x:{0=>1}}
184
184
  b = {x:[1]}
185
185
 
186
- diff = HashDiff.diff(a, b, :array_path => true)
187
- diff.should == [["~", [:a], [1], {0=>1}]]
186
+ diff = Hashdiff.diff(a, b, :array_path => true)
187
+ diff.should == [["~", [:x], {0=>1}, [1]]]
188
188
  ```
189
189
 
190
190
  #### `:use_lcs`
@@ -205,7 +205,7 @@ Note, currently the :similarity option has no effect when :use_lcs is false.
205
205
  a = {x: [0, 1, 2]}
206
206
  b = {x: [0, 2, 2, 3]}
207
207
 
208
- diff = HashDiff.diff(a, b, :use_lcs => false)
208
+ diff = Hashdiff.diff(a, b, :use_lcs => false)
209
209
  diff.should == [["~", "x[1]", 1, 2], ["+", "x[3]", 3]]
210
210
  ```
211
211
 
@@ -217,7 +217,7 @@ It's possible to specify how the values of a key should be compared.
217
217
  a = {a:'car', b:'boat', c:'plane'}
218
218
  b = {a:'bus', b:'truck', c:' plan'}
219
219
 
220
- diff = HashDiff.diff(a, b) do |path, obj1, obj2|
220
+ diff = Hashdiff.diff(a, b) do |path, obj1, obj2|
221
221
  case path
222
222
  when /a|b|c/
223
223
  obj1.length == obj2.length
@@ -233,7 +233,7 @@ The yielded params of the comparison block is `|path, obj1, obj2|`, in which pat
233
233
  a = {a:'car', b:['boat', 'plane'] }
234
234
  b = {a:'bus', b:['truck', ' plan'] }
235
235
 
236
- diff = HashDiff.diff(a, b) do |path, obj1, obj2|
236
+ diff = Hashdiff.diff(a, b) do |path, obj1, obj2|
237
237
  case path
238
238
  when 'b[*]'
239
239
  obj1.length == obj2.length
@@ -255,13 +255,18 @@ An order difference alone between two arrays can create too many diffs to be use
255
255
  a = {a:'car', b:['boat', 'plane'] }
256
256
  b = {a:'car', b:['plane', 'boat'] }
257
257
 
258
- HashDiff.diff(a, b) => [["+", "b[0]", "plane"], ["-", "b[2]", "plane"]]
258
+ Hashdiff.diff(a, b) => [["+", "b[0]", "plane"], ["-", "b[2]", "plane"]]
259
259
 
260
260
  b[:b].sort!
261
261
 
262
- HashDiff.diff(a, b) => []
262
+ Hashdiff.diff(a, b) => []
263
263
  ```
264
264
 
265
+ ## Maintainers
266
+
267
+ - Krzysztof Rybka ([@krzysiek1507](https://github.com/krzysiek1507))
268
+ - Fengyun Liu ([@liufengyun](https://github.com/liufengyun))
269
+
265
270
  ## License
266
271
 
267
- HashDiff is distributed under the MIT-LICENSE.
272
+ Hashdiff is distributed under the MIT-LICENSE.
@@ -1,5 +1,11 @@
1
1
  # Change Log
2
2
 
3
+ ## v0.4.0 2019-05-28
4
+
5
+ * refactoring (#56 #57 #59 #61 krzysiek1507)
6
+ * fix typo in README (#64 @pboling)
7
+ * change HashDiff to Hashdiff (#65 @jfelchner)
8
+
3
9
  ## v0.3.9 2019-04-22
4
10
 
5
11
  * Performance tweak (thanks @krzysiek1507: #51 #52 #53)
@@ -22,7 +28,7 @@
22
28
 
23
29
  ## v0.3.4 2017-05-01
24
30
 
25
- * performance improvement of HashDiff#similar? #31
31
+ * performance improvement of `#similar?` #31
26
32
 
27
33
  ## v0.3.2 2016-12-27
28
34
 
@@ -64,7 +70,7 @@
64
70
  ## v0.0.5 2012-7-1
65
71
 
66
72
  * fix a bug in judging whehter two objects are similiar.
67
- * add more spec test for HashDiff.best_diff
73
+ * add more spec test for `.best_diff`
68
74
 
69
75
  ## v0.0.4 2012-6-24
70
76
 
@@ -5,16 +5,17 @@ require 'hashdiff/version'
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = 'hashdiff'
8
- s.version = HashDiff::VERSION
8
+ s.version = Hashdiff::VERSION
9
9
  s.license = 'MIT'
10
- s.summary = ' HashDiff is a diff lib to compute the smallest difference between two hashes. '
11
- s.description = ' HashDiff is a diff lib to compute the smallest difference between two hashes. '
10
+ s.summary = ' Hashdiff is a diff lib to compute the smallest difference between two hashes. '
11
+ s.description = ' Hashdiff is a diff lib to compute the smallest difference between two hashes. '
12
12
 
13
13
  s.files = `git ls-files`.split("\n")
14
14
  s.test_files = `git ls-files -- Appraisals {spec}/*`.split("\n")
15
15
 
16
16
  s.require_paths = ['lib']
17
17
  s.required_ruby_version = Gem::Requirement.new('>= 2.0.0')
18
+ s.post_install_message = 'The HashDiff constant used by this gem conflicts with another gem of a similar name. As of version 1.0 the HashDiff constant will be completely removed and replaced by Hashdiff. For more information see https://github.com/liufengyun/hashdiff/issues/45.'
18
19
 
19
20
  s.authors = ['Liu Fengyun']
20
21
  s.email = ['liufengyunchina@gmail.com']
@@ -26,4 +27,14 @@ Gem::Specification.new do |s|
26
27
  s.add_development_dependency('rubocop')
27
28
  s.add_development_dependency('rubocop-rspec')
28
29
  s.add_development_dependency('yard')
30
+
31
+ if s.respond_to?(:metadata)
32
+ s.metadata = {
33
+ 'bug_tracker_uri' => 'https://github.com/liufengyun/hashdiff/issues',
34
+ 'changelog_uri' => 'https://github.com/liufengyun/hashdiff/blob/master/changelog.md',
35
+ 'documentation_uri' => 'https://www.rubydoc.info/gems/hashdiff',
36
+ 'homepage_uri' => 'https://github.com/liufengyun/hashdiff',
37
+ 'source_code_uri' => 'https://github.com/liufengyun/hashdiff'
38
+ }
39
+ end
29
40
  end
@@ -1,8 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'hashdiff/util'
4
- require_relative 'hashdiff/lcs'
5
- require_relative 'hashdiff/linear_compare_array'
6
- require_relative 'hashdiff/diff'
7
- require_relative 'hashdiff/patch'
8
- require_relative 'hashdiff/version'
3
+ require 'hashdiff/util'
4
+ require 'hashdiff/compare_hashes'
5
+ require 'hashdiff/lcs'
6
+ require 'hashdiff/lcs_compare_arrays'
7
+ require 'hashdiff/linear_compare_array'
8
+ require 'hashdiff/diff'
9
+ require 'hashdiff/patch'
10
+ require 'hashdiff/version'
11
+
12
+ HashDiff = Hashdiff
13
+
14
+ warn 'The HashDiff constant used by this gem conflicts with another gem of a similar name. As of version 1.0 the HashDiff constant will be completely removed and replaced by Hashdiff. For more information see https://github.com/liufengyun/hashdiff/issues/45.'
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hashdiff
4
+ # @private
5
+ # Used to compare hashes
6
+ class CompareHashes
7
+ class << self
8
+ def call(obj1, obj2, opts = {})
9
+ return [] if obj1.empty? && obj2.empty?
10
+
11
+ obj1_keys = obj1.keys
12
+ obj2_keys = obj2.keys
13
+
14
+ added_keys = (obj2_keys - obj1_keys).sort_by(&:to_s)
15
+ common_keys = (obj1_keys & obj2_keys).sort_by(&:to_s)
16
+ deleted_keys = (obj1_keys - obj2_keys).sort_by(&:to_s)
17
+
18
+ result = []
19
+
20
+ # add deleted properties
21
+ deleted_keys.each do |k|
22
+ change_key = Hashdiff.prefix_append_key(opts[:prefix], k, opts)
23
+ custom_result = Hashdiff.custom_compare(opts[:comparison], change_key, obj1[k], nil)
24
+
25
+ if custom_result
26
+ result.concat(custom_result)
27
+ else
28
+ result << ['-', change_key, obj1[k]]
29
+ end
30
+ end
31
+
32
+ # recursive comparison for common keys
33
+ common_keys.each do |k|
34
+ prefix = Hashdiff.prefix_append_key(opts[:prefix], k, opts)
35
+
36
+ result.concat(Hashdiff.diff(obj1[k], obj2[k], opts.merge(prefix: prefix)))
37
+ end
38
+
39
+ # added properties
40
+ added_keys.each do |k|
41
+ change_key = Hashdiff.prefix_append_key(opts[:prefix], k, opts)
42
+
43
+ custom_result = Hashdiff.custom_compare(opts[:comparison], change_key, nil, obj2[k])
44
+
45
+ if custom_result
46
+ result.concat(custom_result)
47
+ else
48
+ result << ['+', change_key, obj2[k]]
49
+ end
50
+ end
51
+
52
+ result
53
+ end
54
+ end
55
+ end
56
+ end
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module HashDiff
3
+ module Hashdiff
4
4
  # Best diff two objects, which tries to generate the smallest change set using different similarity values.
5
5
  #
6
- # HashDiff.best_diff is useful in case of comparing two objects which include similar hashes in arrays.
6
+ # Hashdiff.best_diff is useful in case of comparing two objects which include similar hashes in arrays.
7
7
  #
8
8
  # @param [Array, Hash] obj1
9
9
  # @param [Array, Hash] obj2
@@ -23,7 +23,7 @@ module HashDiff
23
23
  # @example
24
24
  # a = {'x' => [{'a' => 1, 'c' => 3, 'e' => 5}, {'y' => 3}]}
25
25
  # b = {'x' => [{'a' => 1, 'b' => 2, 'e' => 5}] }
26
- # diff = HashDiff.best_diff(a, b)
26
+ # diff = Hashdiff.best_diff(a, b)
27
27
  # diff.should == [['-', 'x[0].c', 3], ['+', 'x[0].b', 2], ['-', 'x[1].y', 3], ['-', 'x[1]', {}]]
28
28
  #
29
29
  # @since 0.0.1
@@ -69,7 +69,7 @@ module HashDiff
69
69
  # a = {"a" => 1, "b" => {"b1" => 1, "b2" =>2}}
70
70
  # b = {"a" => 1, "b" => {}}
71
71
  #
72
- # diff = HashDiff.diff(a, b)
72
+ # diff = Hashdiff.diff(a, b)
73
73
  # diff.should == [['-', 'b.b1', 1], ['-', 'b.b2', 2]]
74
74
  #
75
75
  # @since 0.0.1
@@ -95,78 +95,19 @@ module HashDiff
95
95
 
96
96
  return [] if obj1.nil? && obj2.nil?
97
97
 
98
- return [['~', opts[:prefix], nil, obj2]] if obj1.nil?
99
-
100
- return [['~', opts[:prefix], obj1, nil]] if obj2.nil?
98
+ return [['~', opts[:prefix], obj1, obj2]] if obj1.nil? || obj2.nil?
101
99
 
102
100
  return [['~', opts[:prefix], obj1, obj2]] unless comparable?(obj1, obj2, opts[:strict])
103
101
 
104
- result = []
105
- if obj1.is_a?(Array) && opts[:use_lcs]
106
- changeset = diff_array_lcs(obj1, obj2, opts) do |lcs|
107
- # use a's index for similarity
108
- lcs.each do |pair|
109
- prefix = prefix_append_array_index(opts[:prefix], pair[0], opts)
110
- result.concat(diff(obj1[pair[0]], obj2[pair[1]], opts.merge(prefix: prefix)))
111
- end
112
- end
113
-
114
- changeset.each do |change|
115
- change_key = prefix_append_array_index(opts[:prefix], change[1], opts)
116
- if change[0] == '-'
117
- result << ['-', change_key, change[2]]
118
- elsif change[0] == '+'
119
- result << ['+', change_key, change[2]]
120
- end
121
- end
122
- elsif obj1.is_a?(Array) && !opts[:use_lcs]
123
- result.concat(LinearCompareArray.call(obj1, obj2, opts))
124
- elsif obj1.is_a?(Hash)
125
- obj1_keys = obj1.keys
126
- obj2_keys = obj2.keys
127
-
128
- deleted_keys = (obj1_keys - obj2_keys).sort_by(&:to_s)
129
- common_keys = (obj1_keys & obj2_keys).sort_by(&:to_s)
130
- added_keys = (obj2_keys - obj1_keys).sort_by(&:to_s)
131
-
132
- # add deleted properties
133
- deleted_keys.each do |k|
134
- change_key = prefix_append_key(opts[:prefix], k, opts)
135
- custom_result = custom_compare(opts[:comparison], change_key, obj1[k], nil)
136
-
137
- if custom_result
138
- result.concat(custom_result)
139
- else
140
- result << ['-', change_key, obj1[k]]
141
- end
142
- end
143
-
144
- # recursive comparison for common keys
145
- common_keys.each do |k|
146
- prefix = prefix_append_key(opts[:prefix], k, opts)
147
- result.concat(diff(obj1[k], obj2[k], opts.merge(prefix: prefix)))
148
- end
102
+ return LcsCompareArrays.call(obj1, obj2, opts) if obj1.is_a?(Array) && opts[:use_lcs]
149
103
 
150
- # added properties
151
- added_keys.each do |k|
152
- change_key = prefix_append_key(opts[:prefix], k, opts)
153
- next if obj1.key?(k)
104
+ return LinearCompareArray.call(obj1, obj2, opts) if obj1.is_a?(Array) && !opts[:use_lcs]
154
105
 
155
- custom_result = custom_compare(opts[:comparison], change_key, nil, obj2[k])
106
+ return CompareHashes.call(obj1, obj2, opts) if obj1.is_a?(Hash)
156
107
 
157
- if custom_result
158
- result.concat(custom_result)
159
- else
160
- result << ['+', change_key, obj2[k]]
161
- end
162
- end
163
- else
164
- return [] if compare_values(obj1, obj2, opts)
165
-
166
- return [['~', opts[:prefix], obj1, obj2]]
167
- end
108
+ return [] if compare_values(obj1, obj2, opts)
168
109
 
169
- result
110
+ [['~', opts[:prefix], obj1, obj2]]
170
111
  end
171
112
 
172
113
  # @private
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module HashDiff
3
+ module Hashdiff
4
4
  # @private
5
5
  #
6
6
  # caculate array difference using LCS algorithm
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hashdiff
4
+ # @private
5
+ # Used to compare arrays using the lcs algorithm
6
+ class LcsCompareArrays
7
+ class << self
8
+ def call(obj1, obj2, opts = {})
9
+ result = []
10
+
11
+ changeset = Hashdiff.diff_array_lcs(obj1, obj2, opts) do |lcs|
12
+ # use a's index for similarity
13
+ lcs.each do |pair|
14
+ prefix = Hashdiff.prefix_append_array_index(opts[:prefix], pair[0], opts)
15
+
16
+ result.concat(Hashdiff.diff(obj1[pair[0]], obj2[pair[1]], opts.merge(prefix: prefix)))
17
+ end
18
+ end
19
+
20
+ changeset.each do |change|
21
+ next if change[0] != '-' && change[0] != '+'
22
+
23
+ change_key = Hashdiff.prefix_append_array_index(opts[:prefix], change[1], opts)
24
+
25
+ result << [change[0], change_key, change[2]]
26
+ end
27
+
28
+ result
29
+ end
30
+ end
31
+ end
32
+ end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module HashDiff
3
+ module Hashdiff
4
4
  # @private
5
5
  #
6
6
  # Used to compare arrays in a linear complexity, which produces longer diffs
@@ -80,8 +80,8 @@ module HashDiff
80
80
  end
81
81
 
82
82
  def item_difference(old_item, new_item, item_index)
83
- prefix = HashDiff.prefix_append_array_index(options[:prefix], item_index, options)
84
- HashDiff.diff(old_item, new_item, options.merge(prefix: prefix))
83
+ prefix = Hashdiff.prefix_append_array_index(options[:prefix], item_index, options)
84
+ Hashdiff.diff(old_item, new_item, options.merge(prefix: prefix))
85
85
  end
86
86
 
87
87
  # look ahead in the new array to see if the current item appears later
@@ -137,12 +137,12 @@ module HashDiff
137
137
  end
138
138
 
139
139
  def append_addition(item, index)
140
- key = HashDiff.prefix_append_array_index(options[:prefix], index, options)
140
+ key = Hashdiff.prefix_append_array_index(options[:prefix], index, options)
141
141
  additions << ['+', key, item]
142
142
  end
143
143
 
144
144
  def append_deletion(item, index)
145
- key = HashDiff.prefix_append_array_index(options[:prefix], index, options)
145
+ key = Hashdiff.prefix_append_array_index(options[:prefix], index, options)
146
146
  deletions << ['-', key, item]
147
147
  end
148
148
 
@@ -3,7 +3,7 @@
3
3
  #
4
4
  # This module provides methods to diff two hash, patch and unpatch hash
5
5
  #
6
- module HashDiff
6
+ module Hashdiff
7
7
  # Apply patch to object
8
8
  #
9
9
  # @param [Hash, Array] obj the object to be patched, can be an Array or a Hash
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module HashDiff
3
+ module Hashdiff
4
4
  # @private
5
5
  #
6
6
  # judge whether two objects are similar
7
7
  def self.similar?(obja, objb, options = {})
8
- return compare_values(obja, objb, options) unless obja.is_a?(Array) || obja.is_a?(Hash) || objb.is_a?(Array) || objb.is_a?(Hash)
8
+ return compare_values(obja, objb, options) if !options[:comparison] && !any_hash_or_array?(obja, objb)
9
9
 
10
10
  count_a = count_nodes(obja)
11
11
  count_b = count_nodes(objb)
@@ -140,4 +140,15 @@ module HashDiff
140
140
  "#{prefix}[#{array_index}]"
141
141
  end
142
142
  end
143
+
144
+ class << self
145
+ private
146
+
147
+ # @private
148
+ #
149
+ # checks if both objects are Arrays or Hashes
150
+ def any_hash_or_array?(obja, objb)
151
+ obja.is_a?(Array) || obja.is_a?(Hash) || objb.is_a?(Array) || objb.is_a?(Hash)
152
+ end
153
+ end
143
154
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module HashDiff
4
- VERSION = '0.3.9'.freeze
3
+ module Hashdiff
4
+ VERSION = '0.4.0'.freeze
5
5
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe HashDiff do
5
+ describe Hashdiff do
6
6
  it 'is able to best diff' do
7
7
  a = { 'x' => [{ 'a' => 1, 'c' => 3, 'e' => 5 }, { 'y' => 3 }] }
8
8
  b = { 'x' => [{ 'a' => 1, 'b' => 2, 'e' => 5 }] }
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe HashDiff do
5
+ describe Hashdiff do
6
6
  it 'is able to diff two equal array' do
7
7
  a = [1, 2, 3]
8
8
  b = [1, 2, 3]
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe HashDiff do
5
+ describe Hashdiff do
6
6
  it 'is able to diff two empty hashes' do
7
7
  diff = described_class.diff({}, {})
8
8
  diff.should == []
@@ -275,6 +275,20 @@ describe HashDiff do
275
275
  end
276
276
  diff.should == [['~', 'b', 'boat', 'truck'], ['~', 'c', 'plane', ' plan']]
277
277
  end
278
+
279
+ it 'compares nested arrays using proc specified in block' do
280
+ a = { a: 'car', b: %w[boat plane] }
281
+ b = { a: 'bus', b: ['truck', ' plan'] }
282
+
283
+ diff = described_class.diff(a, b) do |path, obj1, obj2|
284
+ case path
285
+ when 'b[*]'
286
+ obj1.length == obj2.length
287
+ end
288
+ end
289
+
290
+ expect(diff).to eq [['~', 'a', 'car', 'bus'], ['~', 'b[1]', 'plane', ' plan'], ['-', 'b[0]', 'boat'], ['+', 'b[0]', 'truck']]
291
+ end
278
292
  end
279
293
 
280
294
  context 'when :array_path is true' do
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe HashDiff do
5
+ describe Hashdiff do
6
6
  it 'is able to find LCS between two equal array' do
7
7
  a = [1, 2, 3]
8
8
  b = [1, 2, 3]
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe HashDiff::LinearCompareArray do
5
+ describe Hashdiff::LinearCompareArray do
6
6
  it 'finds no differences between two empty arrays' do
7
7
  difference = described_class.call([], [])
8
8
  difference.should == []
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe HashDiff do
5
+ describe Hashdiff do
6
6
  it 'is able to patch key addition' do
7
7
  a = { 'a' => 3, 'c' => 11, 'd' => 45, 'e' => 100, 'f' => 200 }
8
8
  b = { 'a' => 3, 'c' => 11, 'd' => 45, 'e' => 100, 'f' => 200, 'g' => 300 }
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe HashDiff do
5
+ describe Hashdiff do
6
6
  it 'is able to decode property path' do
7
7
  decoded = described_class.send(:decode_property_path, 'a.b[0].c.city[5]')
8
8
  decoded.should == ['a', 'b', 0, 'c', 'city', 5]
@@ -21,11 +21,11 @@ describe HashDiff do
21
21
  end
22
22
 
23
23
  it 'is able to tell similiar empty hash' do
24
- described_class.similar?({}, {}, 1).should be true
24
+ described_class.similar?({}, {}, similarity: 1).should be true
25
25
  end
26
26
 
27
27
  it 'is able to tell similiar empty array' do
28
- described_class.similar?([], [], 1).should be true
28
+ described_class.similar?([], [], similarity: 1).should be true
29
29
  end
30
30
 
31
31
  it 'is able to tell similiar hash with values within tolerance' do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hashdiff
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.9
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Liu Fengyun
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-04-22 00:00:00.000000000 Z
11
+ date: 2019-05-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bluecloth
@@ -80,7 +80,7 @@ dependencies:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
- description: " HashDiff is a diff lib to compute the smallest difference between two
83
+ description: " Hashdiff is a diff lib to compute the smallest difference between two
84
84
  hashes. "
85
85
  email:
86
86
  - liufengyunchina@gmail.com
@@ -100,25 +100,34 @@ files:
100
100
  - changelog.md
101
101
  - hashdiff.gemspec
102
102
  - lib/hashdiff.rb
103
+ - lib/hashdiff/compare_hashes.rb
103
104
  - lib/hashdiff/diff.rb
104
105
  - lib/hashdiff/lcs.rb
106
+ - lib/hashdiff/lcs_compare_arrays.rb
105
107
  - lib/hashdiff/linear_compare_array.rb
106
108
  - lib/hashdiff/patch.rb
107
109
  - lib/hashdiff/util.rb
108
110
  - lib/hashdiff/version.rb
109
- - spec/hash_diff/best_diff_spec.rb
110
- - spec/hash_diff/diff_array_spec.rb
111
- - spec/hash_diff/diff_spec.rb
112
- - spec/hash_diff/lcs_spec.rb
113
- - spec/hash_diff/linear_compare_array_spec.rb
114
- - spec/hash_diff/patch_spec.rb
115
- - spec/hash_diff/util_spec.rb
111
+ - spec/hashdiff/best_diff_spec.rb
112
+ - spec/hashdiff/diff_array_spec.rb
113
+ - spec/hashdiff/diff_spec.rb
114
+ - spec/hashdiff/lcs_spec.rb
115
+ - spec/hashdiff/linear_compare_array_spec.rb
116
+ - spec/hashdiff/patch_spec.rb
117
+ - spec/hashdiff/util_spec.rb
116
118
  - spec/spec_helper.rb
117
119
  homepage: https://github.com/liufengyun/hashdiff
118
120
  licenses:
119
121
  - MIT
120
- metadata: {}
121
- post_install_message:
122
+ metadata:
123
+ bug_tracker_uri: https://github.com/liufengyun/hashdiff/issues
124
+ changelog_uri: https://github.com/liufengyun/hashdiff/blob/master/changelog.md
125
+ documentation_uri: https://www.rubydoc.info/gems/hashdiff
126
+ homepage_uri: https://github.com/liufengyun/hashdiff
127
+ source_code_uri: https://github.com/liufengyun/hashdiff
128
+ post_install_message: The HashDiff constant used by this gem conflicts with another
129
+ gem of a similar name. As of version 1.0 the HashDiff constant will be completely
130
+ removed and replaced by Hashdiff. For more information see https://github.com/liufengyun/hashdiff/issues/45.
122
131
  rdoc_options: []
123
132
  require_paths:
124
133
  - lib
@@ -137,5 +146,5 @@ rubyforge_project:
137
146
  rubygems_version: 2.5.2.3
138
147
  signing_key:
139
148
  specification_version: 4
140
- summary: HashDiff is a diff lib to compute the smallest difference between two hashes.
149
+ summary: Hashdiff is a diff lib to compute the smallest difference between two hashes.
141
150
  test_files: []