hashdiff 0.3.7 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.rubocop.yml +32 -0
- data/.travis.yml +3 -5
- data/Gemfile +3 -1
- data/README.md +42 -31
- data/Rakefile +9 -4
- data/changelog.md +31 -3
- data/hashdiff.gemspec +26 -12
- data/lib/hashdiff.rb +4 -0
- data/lib/hashdiff/compare_hashes.rb +69 -0
- data/lib/hashdiff/diff.rb +61 -116
- data/lib/hashdiff/lcs.rb +27 -30
- data/lib/hashdiff/lcs_compare_arrays.rb +32 -0
- data/lib/hashdiff/linear_compare_array.rb +10 -6
- data/lib/hashdiff/patch.rb +5 -5
- data/lib/hashdiff/util.rb +44 -35
- data/lib/hashdiff/version.rb +4 -2
- data/spec/hashdiff/best_diff_spec.rb +44 -43
- data/spec/hashdiff/diff_array_spec.rb +19 -19
- data/spec/hashdiff/diff_spec.rb +180 -159
- data/spec/hashdiff/lcs_spec.rb +27 -26
- data/spec/hashdiff/linear_compare_array_spec.rb +20 -18
- data/spec/hashdiff/patch_spec.rb +123 -121
- data/spec/hashdiff/readme_spec.rb +15 -0
- data/spec/hashdiff/util_spec.rb +81 -43
- data/spec/spec_helper.rb +2 -0
- metadata +59 -23
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: a9b50073f973250c144bb05272510f462dda18a7f5c9a8719156065773fdcaaa
|
4
|
+
data.tar.gz: 903439ed3ea22994d072201509506232fb77482506494bbb8c8419dc9fb8d546
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e1c00d4710a67688a35197197da93ac3bfabca5f5a51edc152bfbd341a16548e762ddf2290364b7fc3a20e99cdb6d8d909ff84e766468fe623eb3977afd6d90f
|
7
|
+
data.tar.gz: 2d860929e99458cd89ee60ce877a87557d6bb9d52dcd25e0989f1a0a7b372d026bb646ee2b19498f6637a485f15fcd1e68cf1e1c0dbe666ad5af1792d60a893a
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require: rubocop-rspec
|
2
|
+
AllCops:
|
3
|
+
TargetRubyVersion: 2.0 # always the lowest version we support
|
4
|
+
Metrics/PerceivedComplexity:
|
5
|
+
Enabled: false
|
6
|
+
Metrics/CyclomaticComplexity:
|
7
|
+
Enabled: false
|
8
|
+
Metrics/MethodLength:
|
9
|
+
Enabled: false
|
10
|
+
Metrics/AbcSize:
|
11
|
+
Enabled: false
|
12
|
+
Metrics/LineLength:
|
13
|
+
Enabled: false
|
14
|
+
Metrics/ClassLength:
|
15
|
+
Enabled: false
|
16
|
+
Metrics/BlockLength:
|
17
|
+
Enabled: false
|
18
|
+
Metrics/ModuleLength:
|
19
|
+
Enabled: false
|
20
|
+
Style/Documentation:
|
21
|
+
Enabled: false
|
22
|
+
Style/FrozenStringLiteralComment:
|
23
|
+
Enabled: true
|
24
|
+
EnforcedStyle: always
|
25
|
+
Style/NumericPredicate:
|
26
|
+
Enabled: false
|
27
|
+
Style/RedundantFreeze:
|
28
|
+
Enabled: false
|
29
|
+
RSpec/ExampleLength:
|
30
|
+
Enabled: false
|
31
|
+
RSpec/DescribeClass:
|
32
|
+
Enabled: false
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,14 +1,17 @@
|
|
1
|
-
#
|
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
|
-
|
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
|
-
|
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
|
+
__WARNING__: Don't use the library for comparing large arrays, say ~10K (see #49).
|
13
|
+
|
14
|
+
## Why Hashdiff?
|
12
15
|
|
13
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?
|
14
17
|
|
@@ -18,7 +21,7 @@ An algorithm that responds to this question has to do following:
|
|
18
21
|
* Compute recursively -- Arrays and Hashes may be nested arbitrarily in A or B.
|
19
22
|
* Compute the smallest change -- it should recognize similar child Hashes or child Arrays between A and B.
|
20
23
|
|
21
|
-
|
24
|
+
Hashdiff answers the question above using an opinionated approach:
|
22
25
|
|
23
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]`.
|
24
27
|
* The change set can be represented using the dot-syntax representation. For example, `[['-', 'b.x', 3], ['~', 'b.z', 45, 30], ['+', 'b.y', 3]]`.
|
@@ -29,7 +32,7 @@ HashDiff answers the question above using an opinionated approach:
|
|
29
32
|
|
30
33
|
To use the gem, add the following to your Gemfile:
|
31
34
|
|
32
|
-
```
|
35
|
+
```Ruby
|
33
36
|
gem 'hashdiff'
|
34
37
|
```
|
35
38
|
|
@@ -43,7 +46,7 @@ Two simple hashes:
|
|
43
46
|
a = {a:3, b:2}
|
44
47
|
b = {}
|
45
48
|
|
46
|
-
diff =
|
49
|
+
diff = Hashdiff.diff(a, b)
|
47
50
|
diff.should == [['-', 'a', 3], ['-', 'b', 2]]
|
48
51
|
```
|
49
52
|
|
@@ -53,7 +56,7 @@ More complex hashes:
|
|
53
56
|
a = {a:{x:2, y:3, z:4}, b:{x:3, z:45}}
|
54
57
|
b = {a:{y:3}, b:{y:3, z:30}}
|
55
58
|
|
56
|
-
diff =
|
59
|
+
diff = Hashdiff.diff(a, b)
|
57
60
|
diff.should == [['-', 'a.x', 2], ['-', 'a.z', 4], ['-', 'b.x', 3], ['~', 'b.z', 45, 30], ['+', 'b.y', 3]]
|
58
61
|
```
|
59
62
|
|
@@ -63,7 +66,7 @@ Arrays in hashes:
|
|
63
66
|
a = {a:[{x:2, y:3, z:4}, {x:11, y:22, z:33}], b:{x:3, z:45}}
|
64
67
|
b = {a:[{y:3}, {x:11, z:33}], b:{y:22}}
|
65
68
|
|
66
|
-
diff =
|
69
|
+
diff = Hashdiff.best_diff(a, b)
|
67
70
|
diff.should == [['-', 'a[0].x', 2], ['-', 'a[0].z', 4], ['-', 'a[1].y', 22], ['-', 'b.x', 3], ['-', 'b.z', 45], ['+', 'b.y', 22]]
|
68
71
|
```
|
69
72
|
|
@@ -75,8 +78,8 @@ patch example:
|
|
75
78
|
a = {'a' => 3}
|
76
79
|
b = {'a' => {'a1' => 1, 'a2' => 2}}
|
77
80
|
|
78
|
-
diff =
|
79
|
-
|
81
|
+
diff = Hashdiff.diff(a, b)
|
82
|
+
Hashdiff.patch!(a, diff).should == b
|
80
83
|
```
|
81
84
|
|
82
85
|
unpatch example:
|
@@ -85,15 +88,15 @@ unpatch example:
|
|
85
88
|
a = [{'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5}, {'x' => 5, 'y' => 6, 'z' => 3}, 1]
|
86
89
|
b = [1, {'a' => 1, 'b' => 2, 'c' => 3, 'e' => 5}]
|
87
90
|
|
88
|
-
diff =
|
89
|
-
|
91
|
+
diff = Hashdiff.diff(a, b) # diff two array is OK
|
92
|
+
Hashdiff.unpatch!(b, diff).should == a
|
90
93
|
```
|
91
94
|
|
92
95
|
### Options
|
93
96
|
|
94
97
|
There are eight options available: `:delimiter`, `:similarity`,
|
95
|
-
`:strict`, `:numeric_tolerance`, `:strip`, `:case_insensitive`,
|
96
|
-
and `:use_lcs`
|
98
|
+
`:strict`, `:indifferent`, `:numeric_tolerance`, `:strip`, `:case_insensitive`,
|
99
|
+
`:array_path` and `:use_lcs`
|
97
100
|
|
98
101
|
#### `:delimiter`
|
99
102
|
|
@@ -103,7 +106,7 @@ You can specify `:delimiter` to be something other than the default dot. For exa
|
|
103
106
|
a = {a:{x:2, y:3, z:4}, b:{x:3, z:45}}
|
104
107
|
b = {a:{y:3}, b:{y:3, z:30}}
|
105
108
|
|
106
|
-
diff =
|
109
|
+
diff = Hashdiff.diff(a, b, delimiter: '\t')
|
107
110
|
diff.should == [['-', 'a\tx', 2], ['-', 'a\tz', 4], ['-', 'b\tx', 3], ['~', 'b\tz', 45, 30], ['+', 'b\ty', 3]]
|
108
111
|
```
|
109
112
|
|
@@ -113,7 +116,11 @@ In cases where you have similar hash objects in arrays, you can pass a custom va
|
|
113
116
|
|
114
117
|
#### `:strict`
|
115
118
|
|
116
|
-
The `:strict` option, which defaults to `true`, specifies whether numeric types are compared on type as well as value. By default,
|
119
|
+
The `:strict` option, which defaults to `true`, specifies whether numeric types are compared on type as well as value. By default, an Integer will never be equal to a Float (e.g. 4 != 4.0). Setting `:strict` to false makes the comparison looser (e.g. 4 == 4.0).
|
120
|
+
|
121
|
+
#### `:indifferent`
|
122
|
+
|
123
|
+
The `:indifferent` option, which defaults to `false`, specifies whether to treat hash keys indifferently. Setting `:indifferent` to true has the effect of ignoring differences between symbol keys (ie. {a: 1} ~= {'a' => 1})
|
117
124
|
|
118
125
|
#### `:numeric_tolerance`
|
119
126
|
|
@@ -123,7 +130,7 @@ The :numeric_tolerance option allows for a small numeric tolerance.
|
|
123
130
|
a = {x:5, y:3.75, z:7}
|
124
131
|
b = {x:6, y:3.76, z:7}
|
125
132
|
|
126
|
-
diff =
|
133
|
+
diff = Hashdiff.diff(a, b, numeric_tolerance: 0.1)
|
127
134
|
diff.should == [["~", "x", 5, 6]]
|
128
135
|
```
|
129
136
|
|
@@ -135,7 +142,7 @@ The :strip option strips all strings before comparing.
|
|
135
142
|
a = {x:5, s:'foo '}
|
136
143
|
b = {x:6, s:'foo'}
|
137
144
|
|
138
|
-
diff =
|
145
|
+
diff = Hashdiff.diff(a, b, numeric_tolerance: 0.1, strip: true)
|
139
146
|
diff.should == [["~", "x", 5, 6]]
|
140
147
|
```
|
141
148
|
|
@@ -147,7 +154,7 @@ The :case_insensitive option makes string comparisons ignore case.
|
|
147
154
|
a = {x:5, s:'FooBar'}
|
148
155
|
b = {x:6, s:'foobar'}
|
149
156
|
|
150
|
-
diff =
|
157
|
+
diff = Hashdiff.diff(a, b, numeric_tolerance: 0.1, case_insensitive: true)
|
151
158
|
diff.should == [["~", "x", 5, 6]]
|
152
159
|
```
|
153
160
|
|
@@ -161,7 +168,7 @@ is useful for `patch!` when used on hashes without string keys.
|
|
161
168
|
a = {x:5}
|
162
169
|
b = {'x'=>6}
|
163
170
|
|
164
|
-
diff =
|
171
|
+
diff = Hashdiff.diff(a, b, array_path: true)
|
165
172
|
diff.should == [['-', [:x], 5], ['+', ['x'], 6]]
|
166
173
|
```
|
167
174
|
|
@@ -170,7 +177,7 @@ For cases where there are arrays in paths their index will be added to the path.
|
|
170
177
|
a = {x:[0,1]}
|
171
178
|
b = {x:[0,2]}
|
172
179
|
|
173
|
-
diff =
|
180
|
+
diff = Hashdiff.diff(a, b, array_path: true)
|
174
181
|
diff.should == [["-", [:x, 1], 1], ["+", [:x, 1], 2]]
|
175
182
|
```
|
176
183
|
|
@@ -180,8 +187,8 @@ This shouldn't cause problems if you are comparing an array with a hash:
|
|
180
187
|
a = {x:{0=>1}}
|
181
188
|
b = {x:[1]}
|
182
189
|
|
183
|
-
diff =
|
184
|
-
diff.should == [["~", [:
|
190
|
+
diff = Hashdiff.diff(a, b, array_path: true)
|
191
|
+
diff.should == [["~", [:x], {0=>1}, [1]]]
|
185
192
|
```
|
186
193
|
|
187
194
|
#### `:use_lcs`
|
@@ -202,7 +209,7 @@ Note, currently the :similarity option has no effect when :use_lcs is false.
|
|
202
209
|
a = {x: [0, 1, 2]}
|
203
210
|
b = {x: [0, 2, 2, 3]}
|
204
211
|
|
205
|
-
diff =
|
212
|
+
diff = Hashdiff.diff(a, b, use_lcs: false)
|
206
213
|
diff.should == [["~", "x[1]", 1, 2], ["+", "x[3]", 3]]
|
207
214
|
```
|
208
215
|
|
@@ -214,7 +221,7 @@ It's possible to specify how the values of a key should be compared.
|
|
214
221
|
a = {a:'car', b:'boat', c:'plane'}
|
215
222
|
b = {a:'bus', b:'truck', c:' plan'}
|
216
223
|
|
217
|
-
diff =
|
224
|
+
diff = Hashdiff.diff(a, b) do |path, obj1, obj2|
|
218
225
|
case path
|
219
226
|
when /a|b|c/
|
220
227
|
obj1.length == obj2.length
|
@@ -230,7 +237,7 @@ The yielded params of the comparison block is `|path, obj1, obj2|`, in which pat
|
|
230
237
|
a = {a:'car', b:['boat', 'plane'] }
|
231
238
|
b = {a:'bus', b:['truck', ' plan'] }
|
232
239
|
|
233
|
-
diff =
|
240
|
+
diff = Hashdiff.diff(a, b) do |path, obj1, obj2|
|
234
241
|
case path
|
235
242
|
when 'b[*]'
|
236
243
|
obj1.length == obj2.length
|
@@ -252,14 +259,18 @@ An order difference alone between two arrays can create too many diffs to be use
|
|
252
259
|
a = {a:'car', b:['boat', 'plane'] }
|
253
260
|
b = {a:'car', b:['plane', 'boat'] }
|
254
261
|
|
255
|
-
|
262
|
+
Hashdiff.diff(a, b).should == [["+", "b[0]", "plane"], ["-", "b[2]", "plane"]]
|
256
263
|
|
257
264
|
b[:b].sort!
|
258
265
|
|
259
|
-
|
266
|
+
Hashdiff.diff(a, b).should == []
|
260
267
|
```
|
261
268
|
|
262
|
-
##
|
269
|
+
## Maintainers
|
263
270
|
|
264
|
-
|
271
|
+
- Krzysztof Rybka ([@krzysiek1507](https://github.com/krzysiek1507))
|
272
|
+
- Fengyun Liu ([@liufengyun](https://github.com/liufengyun))
|
273
|
+
|
274
|
+
## License
|
265
275
|
|
276
|
+
Hashdiff is distributed under the MIT-LICENSE.
|
data/Rakefile
CHANGED
@@ -1,13 +1,18 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
$LOAD_PATH.push File.expand_path('lib', __dir__)
|
4
|
+
|
5
|
+
require 'rubocop/rake_task'
|
2
6
|
|
3
7
|
require 'bundler'
|
4
8
|
Bundler::GemHelper.install_tasks
|
5
9
|
|
6
10
|
require 'rspec/core/rake_task'
|
7
11
|
|
8
|
-
|
12
|
+
RuboCop::RakeTask.new
|
13
|
+
|
14
|
+
task default: %w[spec rubocop]
|
9
15
|
|
10
16
|
RSpec::Core::RakeTask.new(:spec) do |spec|
|
11
|
-
spec.pattern =
|
17
|
+
spec.pattern = './spec/**/*_spec.rb'
|
12
18
|
end
|
13
|
-
|
data/changelog.md
CHANGED
@@ -1,5 +1,34 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
## v1.0.1 2020-02-25
|
4
|
+
|
5
|
+
* Add indifferent option
|
6
|
+
|
7
|
+
## v1.0.0 2019-06-06
|
8
|
+
|
9
|
+
* Fix typo in readme (#72 @koic)
|
10
|
+
* Fix Rubocop offence (#73 @koic)
|
11
|
+
* Bumps version to v1.0.0 (#74 @jfelchner)
|
12
|
+
|
13
|
+
## v1.0.0.beta1 2019-06-06
|
14
|
+
|
15
|
+
* fix warnings in ci (#69 @y-yagi)
|
16
|
+
* drop warnings of the constant change (#70 @jfelchner)
|
17
|
+
|
18
|
+
## v0.4.0 2019-05-28
|
19
|
+
|
20
|
+
* refactoring (#56 #57 #59 #61 krzysiek1507)
|
21
|
+
* fix typo in README (#64 @pboling)
|
22
|
+
* change HashDiff to Hashdiff (#65 @jfelchner)
|
23
|
+
|
24
|
+
## v0.3.9 2019-04-22
|
25
|
+
|
26
|
+
* Performance tweak (thanks @krzysiek1507: #51 #52 #53)
|
27
|
+
|
28
|
+
## v0.3.8 2018-12-30
|
29
|
+
|
30
|
+
* Add Rubocop and drops Ruby 1.9 support #47
|
31
|
+
|
3
32
|
## v0.3.7 2017-10-08
|
4
33
|
|
5
34
|
* remove 1.8.7 support from gemspec #39
|
@@ -14,7 +43,7 @@
|
|
14
43
|
|
15
44
|
## v0.3.4 2017-05-01
|
16
45
|
|
17
|
-
* performance improvement of
|
46
|
+
* performance improvement of `#similar?` #31
|
18
47
|
|
19
48
|
## v0.3.2 2016-12-27
|
20
49
|
|
@@ -56,7 +85,7 @@
|
|
56
85
|
## v0.0.5 2012-7-1
|
57
86
|
|
58
87
|
* fix a bug in judging whehter two objects are similiar.
|
59
|
-
* add more spec test for
|
88
|
+
* add more spec test for `.best_diff`
|
60
89
|
|
61
90
|
## v0.0.4 2012-6-24
|
62
91
|
|
@@ -69,4 +98,3 @@ For example, `diff({a:2, c:[4, 5]}, {a:2}) will generate following output:
|
|
69
98
|
instead of following:
|
70
99
|
|
71
100
|
[['-', 'c[0]', 4], ['-', 'c[1]', 5], ['-', 'c', []]]
|
72
|
-
|
data/hashdiff.gemspec
CHANGED
@@ -1,25 +1,39 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
$LOAD_PATH << File.expand_path('lib', __dir__)
|
2
4
|
require 'hashdiff/version'
|
3
5
|
|
4
6
|
Gem::Specification.new do |s|
|
5
|
-
s.name =
|
6
|
-
s.version =
|
7
|
+
s.name = 'hashdiff'
|
8
|
+
s.version = Hashdiff::VERSION
|
7
9
|
s.license = 'MIT'
|
8
|
-
s.summary =
|
9
|
-
s.description =
|
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
12
|
|
11
13
|
s.files = `git ls-files`.split("\n")
|
12
14
|
s.test_files = `git ls-files -- Appraisals {spec}/*`.split("\n")
|
13
15
|
|
14
16
|
s.require_paths = ['lib']
|
15
|
-
s.required_ruby_version = Gem::Requirement.new(
|
17
|
+
s.required_ruby_version = Gem::Requirement.new('>= 2.0.0')
|
18
|
+
|
19
|
+
s.authors = ['Liu Fengyun']
|
20
|
+
s.email = ['liufengyunchina@gmail.com']
|
16
21
|
|
17
|
-
s.
|
18
|
-
s.email = ["liufengyunchina@gmail.com"]
|
22
|
+
s.homepage = 'https://github.com/liufengyun/hashdiff'
|
19
23
|
|
20
|
-
s.
|
24
|
+
s.add_development_dependency('bluecloth')
|
25
|
+
s.add_development_dependency('rspec', '~> 2.0')
|
26
|
+
s.add_development_dependency('rubocop', '~> 0.49.1') # last version that works with ruby 2.0
|
27
|
+
s.add_development_dependency('rubocop-rspec')
|
28
|
+
s.add_development_dependency('yard')
|
21
29
|
|
22
|
-
s.
|
23
|
-
|
24
|
-
|
30
|
+
if s.respond_to?(:metadata)
|
31
|
+
s.metadata = {
|
32
|
+
'bug_tracker_uri' => 'https://github.com/liufengyun/hashdiff/issues',
|
33
|
+
'changelog_uri' => 'https://github.com/liufengyun/hashdiff/blob/master/changelog.md',
|
34
|
+
'documentation_uri' => 'https://www.rubydoc.info/gems/hashdiff',
|
35
|
+
'homepage_uri' => 'https://github.com/liufengyun/hashdiff',
|
36
|
+
'source_code_uri' => 'https://github.com/liufengyun/hashdiff'
|
37
|
+
}
|
38
|
+
end
|
25
39
|
end
|
data/lib/hashdiff.rb
CHANGED
@@ -0,0 +1,69 @@
|
|
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
|
+
obj1_lookup = {}
|
14
|
+
obj2_lookup = {}
|
15
|
+
|
16
|
+
if opts[:indifferent]
|
17
|
+
obj1_lookup = obj1_keys.each_with_object({}) { |k, h| h[k.to_s] = k }
|
18
|
+
obj2_lookup = obj2_keys.each_with_object({}) { |k, h| h[k.to_s] = k }
|
19
|
+
obj1_keys = obj1_keys.map { |k| k.is_a?(Symbol) ? k.to_s : k }
|
20
|
+
obj2_keys = obj2_keys.map { |k| k.is_a?(Symbol) ? k.to_s : k }
|
21
|
+
end
|
22
|
+
|
23
|
+
added_keys = (obj2_keys - obj1_keys).sort_by(&:to_s)
|
24
|
+
common_keys = (obj1_keys & obj2_keys).sort_by(&:to_s)
|
25
|
+
deleted_keys = (obj1_keys - obj2_keys).sort_by(&:to_s)
|
26
|
+
|
27
|
+
result = []
|
28
|
+
|
29
|
+
# add deleted properties
|
30
|
+
deleted_keys.each do |k|
|
31
|
+
k = opts[:indifferent] ? obj1_lookup[k] : k
|
32
|
+
change_key = Hashdiff.prefix_append_key(opts[:prefix], k, opts)
|
33
|
+
custom_result = Hashdiff.custom_compare(opts[:comparison], change_key, obj1[k], nil)
|
34
|
+
|
35
|
+
if custom_result
|
36
|
+
result.concat(custom_result)
|
37
|
+
else
|
38
|
+
result << ['-', change_key, obj1[k]]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# recursive comparison for common keys
|
43
|
+
common_keys.each do |k|
|
44
|
+
prefix = Hashdiff.prefix_append_key(opts[:prefix], k, opts)
|
45
|
+
|
46
|
+
k1 = opts[:indifferent] ? obj1_lookup[k] : k
|
47
|
+
k2 = opts[:indifferent] ? obj2_lookup[k] : k
|
48
|
+
result.concat(Hashdiff.diff(obj1[k1], obj2[k2], opts.merge(prefix: prefix)))
|
49
|
+
end
|
50
|
+
|
51
|
+
# added properties
|
52
|
+
added_keys.each do |k|
|
53
|
+
change_key = Hashdiff.prefix_append_key(opts[:prefix], k, opts)
|
54
|
+
|
55
|
+
k = opts[:indifferent] ? obj2_lookup[k] : k
|
56
|
+
custom_result = Hashdiff.custom_compare(opts[:comparison], change_key, nil, obj2[k])
|
57
|
+
|
58
|
+
if custom_result
|
59
|
+
result.concat(custom_result)
|
60
|
+
else
|
61
|
+
result << ['+', change_key, obj2[k]]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
result
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|