hashdiff 0.3.9 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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: []