hashdiff 1.1.0 → 1.2.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 +4 -4
- data/.github/workflows/ci.yml +27 -0
- data/.rubocop.yml +4 -2
- data/README.md +42 -14
- data/changelog.md +16 -1
- data/hashdiff.gemspec +1 -1
- data/lib/hashdiff/compare_hashes.rb +61 -31
- data/lib/hashdiff/diff.rb +7 -4
- data/lib/hashdiff/version.rb +1 -1
- metadata +7 -15
- data/spec/hashdiff/best_diff_spec.rb +0 -75
- data/spec/hashdiff/diff_array_spec.rb +0 -60
- data/spec/hashdiff/diff_spec.rb +0 -375
- data/spec/hashdiff/lcs_spec.rb +0 -76
- data/spec/hashdiff/linear_compare_array_spec.rb +0 -50
- data/spec/hashdiff/patch_spec.rb +0 -185
- data/spec/hashdiff/readme_spec.rb +0 -15
- data/spec/hashdiff/util_spec.rb +0 -116
- data/spec/spec_helper.rb +0 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4752d45ff706f5b763bb7bc2b6b6c4302657caad5e45fce2d02730d962ef3d31
|
4
|
+
data.tar.gz: 5d9ff9c909184d3bbd798a3dbc8ea82d1c2752450c0c04671755aaa0d8d34c25
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6ee25347a9b92ec1ff0849c319221101d2a53c0194586227395d79ced3d7d4172a3a3448ca197886ae175dcc2ab5f681d13790f4a75d69b3c31cec8150c82779
|
7
|
+
data.tar.gz: 0da5f54d158ad5dbe806bd0c25279554c6e47d22faff4334ae427351ff00cca338ea490fb96246611cde5b505d9970b9216b8d6de5960a0532a349f738e0ed52
|
@@ -0,0 +1,27 @@
|
|
1
|
+
name: ci
|
2
|
+
|
3
|
+
on:
|
4
|
+
- pull_request
|
5
|
+
- push
|
6
|
+
|
7
|
+
jobs:
|
8
|
+
build:
|
9
|
+
strategy:
|
10
|
+
fail-fast: false
|
11
|
+
matrix:
|
12
|
+
ruby:
|
13
|
+
- 2.7
|
14
|
+
- '3.0'
|
15
|
+
- 3.1
|
16
|
+
- 3.2
|
17
|
+
- 3.3
|
18
|
+
runs-on: ubuntu-latest
|
19
|
+
steps:
|
20
|
+
- uses: actions/checkout@v4
|
21
|
+
- name: Set up Ruby
|
22
|
+
uses: ruby/setup-ruby@v1
|
23
|
+
with:
|
24
|
+
ruby-version: ${{ matrix.ruby }}
|
25
|
+
bundler-cache: true # 'bundle install' and cache gems
|
26
|
+
- name: Run rake
|
27
|
+
run: bundle exec rake
|
data/.rubocop.yml
CHANGED
@@ -9,7 +9,7 @@ Metrics/MethodLength:
|
|
9
9
|
Enabled: false
|
10
10
|
Metrics/AbcSize:
|
11
11
|
Enabled: false
|
12
|
-
|
12
|
+
Layout/LineLength:
|
13
13
|
Enabled: false
|
14
14
|
Metrics/ClassLength:
|
15
15
|
Enabled: false
|
@@ -36,5 +36,7 @@ RSpec/ExampleLength:
|
|
36
36
|
Enabled: false
|
37
37
|
RSpec/DescribeClass:
|
38
38
|
Enabled: false
|
39
|
-
RSpec/
|
39
|
+
RSpec/SpecFilePathFormat:
|
40
|
+
Enabled: false
|
41
|
+
RSpec/NoExpectationExample:
|
40
42
|
Enabled: false
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Hashdiff [](https://github.com/liufengyun/hashdiff/actions?query=workflow%3Aci) [](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
|
|
@@ -95,7 +95,8 @@ Hashdiff.unpatch!(b, diff).should == a
|
|
95
95
|
### Options
|
96
96
|
|
97
97
|
The following options are available: `:delimiter`, `:similarity`, `:strict`, `:ignore_keys`,
|
98
|
-
`:indifferent`, `:numeric_tolerance`, `:strip`, `:case_insensitive`, `:array_path
|
98
|
+
`:indifferent`, `:numeric_tolerance`, `:strip`, `:case_insensitive`, `:array_path`,
|
99
|
+
`:use_lcs`, and `:preserve_key_order`
|
99
100
|
|
100
101
|
#### `:delimiter`
|
101
102
|
|
@@ -119,23 +120,26 @@ The `:strict` option, which defaults to `true`, specifies whether numeric types
|
|
119
120
|
|
120
121
|
#### `:ignore_keys`
|
121
122
|
|
122
|
-
The `:ignore_keys` option allows you to specify one or more keys to ignore, which defaults to `[]` (none). Ignored keys are ignored at all levels. For example:
|
123
|
+
The `:ignore_keys` option allows you to specify one or more keys to ignore, which defaults to `[]` (none). Ignored keys are ignored at all levels in both hashes. For example:
|
123
124
|
|
124
125
|
```ruby
|
125
|
-
a = { a:
|
126
|
-
b = { a:
|
127
|
-
diff = Hashdiff.diff(a, b, ignore_keys:
|
128
|
-
diff.should == [['~', 'c',
|
126
|
+
a = { a: 4, g: 0, b: { a: 5, c: 6, e: 1 } }
|
127
|
+
b = { b: { a: 7, c: 3, f: 1 }, d: 8 }
|
128
|
+
diff = Hashdiff.diff(a, b, ignore_keys: %i[a f])
|
129
|
+
diff.should == [['-', 'g', 0], ['-', 'b.e', 1], ['~', 'b.c', 6, 3], ['+', 'd', 8]]
|
129
130
|
```
|
130
|
-
If you wish instead to ignore keys at a particlar level you should
|
131
|
-
use a [custom comparison method](https://github.com/liufengyun/hashdiff#specifying-a-custom-comparison-method) instead. For example:
|
131
|
+
If you wish instead to ignore keys at a particlar level you should
|
132
|
+
use a [custom comparison method](https://github.com/liufengyun/hashdiff#specifying-a-custom-comparison-method) instead. For example to diff only at the 2nd level of both hashes:
|
132
133
|
|
133
134
|
```ruby
|
134
|
-
a = { a:
|
135
|
-
b = { a:
|
136
|
-
diff = Hashdiff.diff(a, b)
|
137
|
-
|
138
|
-
|
135
|
+
a = { a: 4, g: 0, b: { a: 5, c: 6, e: 1 } }
|
136
|
+
b = { b: { a: 7, c: 3, f: 1 }, d: 8 }
|
137
|
+
diff = Hashdiff.diff(a, b) do |path, _e, _a|
|
138
|
+
arr = path.split('.')
|
139
|
+
true if %w[a f].include?(arr.last) && arr.size == 2 # note '.' is the default delimiter
|
140
|
+
end
|
141
|
+
diff.should == [['-', 'a', 4], ['-', 'g', 0], ['-', 'b.e', 1], ['~', 'b.c', 6, 3], ['+', 'd', 8]]
|
142
|
+
```
|
139
143
|
|
140
144
|
#### `:indifferent`
|
141
145
|
|
@@ -232,6 +236,30 @@ diff = Hashdiff.diff(a, b, use_lcs: false)
|
|
232
236
|
diff.should == [["~", "x[1]", 1, 2], ["+", "x[3]", 3]]
|
233
237
|
```
|
234
238
|
|
239
|
+
#### `:preserve_key_order`
|
240
|
+
|
241
|
+
By default, the change set is ordered by operation type: deletions (-) first, then updates (~), and finally additions (+).
|
242
|
+
Within each operation group, keys are sorted alphabetically:
|
243
|
+
|
244
|
+
```ruby
|
245
|
+
a = {d: 1, c: 1, a: 1}
|
246
|
+
b = {d: 2, b: 2, a: 2}
|
247
|
+
|
248
|
+
diff = Hashdiff.diff(a, b)
|
249
|
+
diff.should == [["-", "c", 1], ["~", "a", 1, 2], ["~", "d", 1, 2], ["+", "b", 2]]
|
250
|
+
```
|
251
|
+
|
252
|
+
Setting :preserve_key_order to true processes keys in the order they appear in the first hash.
|
253
|
+
Keys that only exist in the second hash are appended in their original order:
|
254
|
+
|
255
|
+
```ruby
|
256
|
+
a = {d: 1, c: 1, a: 1}
|
257
|
+
b = {d: 2, b: 2, a: 2}
|
258
|
+
|
259
|
+
diff = Hashdiff.diff(a, b, preserve_key_order: true)
|
260
|
+
diff.should == [["~", "d", 1, 2], ["-", "c", 1], ["~", "a", 1, 2], ["+", "b", 2]]
|
261
|
+
```
|
262
|
+
|
235
263
|
#### Specifying a custom comparison method
|
236
264
|
|
237
265
|
It's possible to specify how the values of a key should be compared.
|
data/changelog.md
CHANGED
@@ -1,6 +1,21 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
-
## v1.
|
3
|
+
## v1.2.0 2025-5-20
|
4
|
+
|
5
|
+
* Added :preserve_key_order option to maintain original hash key order #99 (@robkiessling)
|
6
|
+
|
7
|
+
## v1.1.2 2024-11-12
|
8
|
+
|
9
|
+
* Fix bundler cache #96 (@olleolleolle)
|
10
|
+
* Quote the '3.0' in YAML #95 (@olleolleolle)
|
11
|
+
* Fix version in source code #97 (@liufengyun)
|
12
|
+
|
13
|
+
## v1.1.1 2024-08-02
|
14
|
+
|
15
|
+
* Fix bug in ignore_keys option #88 (@Matzfan)
|
16
|
+
* Exclude spec files from gem package #94 (@amatsuda)
|
17
|
+
|
18
|
+
## v1.1.0 2023-12-14
|
4
19
|
|
5
20
|
* Add ignore_keys option (#86 @Matzfan)
|
6
21
|
* Remove pinned version of rake < 11
|
data/hashdiff.gemspec
CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |s|
|
|
10
10
|
s.summary = ' Hashdiff is a diff lib to compute the smallest difference between two hashes. '
|
11
11
|
s.description = ' Hashdiff is a diff lib to compute the smallest difference between two hashes. '
|
12
12
|
|
13
|
-
s.files = `git ls-files`.split("\n")
|
13
|
+
s.files = `git ls-files`.split("\n").grep_v(%r{^spec/})
|
14
14
|
s.test_files = `git ls-files -- Appraisals {spec}/*`.split("\n")
|
15
15
|
|
16
16
|
s.require_paths = ['lib']
|
@@ -20,48 +20,78 @@ module Hashdiff
|
|
20
20
|
obj2_keys = obj2_keys.map { |k| k.is_a?(Symbol) ? k.to_s : k }
|
21
21
|
end
|
22
22
|
|
23
|
-
added_keys =
|
24
|
-
common_keys =
|
25
|
-
deleted_keys =
|
23
|
+
added_keys = obj2_keys - obj1_keys
|
24
|
+
common_keys = obj1_keys & obj2_keys
|
25
|
+
deleted_keys = obj1_keys - obj2_keys
|
26
26
|
|
27
27
|
result = []
|
28
28
|
|
29
|
-
opts[:ignore_keys].each
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
k = opts[:indifferent] ? obj1_lookup[k] : k
|
34
|
-
change_key = Hashdiff.prefix_append_key(opts[:prefix], k, opts)
|
35
|
-
custom_result = Hashdiff.custom_compare(opts[:comparison], change_key, obj1[k], nil)
|
36
|
-
|
37
|
-
if custom_result
|
38
|
-
result.concat(custom_result)
|
39
|
-
else
|
40
|
-
result << ['-', change_key, obj1[k]]
|
41
|
-
end
|
29
|
+
opts[:ignore_keys].each do |k|
|
30
|
+
added_keys.delete k
|
31
|
+
common_keys.delete k
|
32
|
+
deleted_keys.delete k
|
42
33
|
end
|
43
34
|
|
44
|
-
|
45
|
-
|
46
|
-
|
35
|
+
handle_key = lambda do |k, type|
|
36
|
+
case type
|
37
|
+
when :deleted
|
38
|
+
# add deleted properties
|
39
|
+
k = opts[:indifferent] ? obj1_lookup[k] : k
|
40
|
+
change_key = Hashdiff.prefix_append_key(opts[:prefix], k, opts)
|
41
|
+
custom_result = Hashdiff.custom_compare(opts[:comparison], change_key, obj1[k], nil)
|
47
42
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
43
|
+
if custom_result
|
44
|
+
result.concat(custom_result)
|
45
|
+
else
|
46
|
+
result << ['-', change_key, obj1[k]]
|
47
|
+
end
|
48
|
+
when :common
|
49
|
+
# recursive comparison for common keys
|
50
|
+
prefix = Hashdiff.prefix_append_key(opts[:prefix], k, opts)
|
52
51
|
|
53
|
-
|
54
|
-
|
55
|
-
|
52
|
+
k1 = opts[:indifferent] ? obj1_lookup[k] : k
|
53
|
+
k2 = opts[:indifferent] ? obj2_lookup[k] : k
|
54
|
+
result.concat(Hashdiff.diff(obj1[k1], obj2[k2], opts.merge(prefix: prefix)))
|
55
|
+
when :added
|
56
|
+
# added properties
|
57
|
+
change_key = Hashdiff.prefix_append_key(opts[:prefix], k, opts)
|
56
58
|
|
57
|
-
|
58
|
-
|
59
|
+
k = opts[:indifferent] ? obj2_lookup[k] : k
|
60
|
+
custom_result = Hashdiff.custom_compare(opts[:comparison], change_key, nil, obj2[k])
|
59
61
|
|
60
|
-
|
61
|
-
|
62
|
+
if custom_result
|
63
|
+
result.concat(custom_result)
|
64
|
+
else
|
65
|
+
result << ['+', change_key, obj2[k]]
|
66
|
+
end
|
62
67
|
else
|
63
|
-
|
68
|
+
raise "Invalid type: #{type}"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
if opts[:preserve_key_order]
|
73
|
+
# Building lookups to speed up key classification
|
74
|
+
added_keys_lookup = added_keys.each_with_object({}) { |k, h| h[k] = true }
|
75
|
+
common_keys_lookup = common_keys.each_with_object({}) { |k, h| h[k] = true }
|
76
|
+
deleted_keys_lookup = deleted_keys.each_with_object({}) { |k, h| h[k] = true }
|
77
|
+
|
78
|
+
# Iterate through all keys, preserving obj1's key order and appending any new keys from obj2. Shared keys
|
79
|
+
# (found in both obj1 and obj2) follow obj1's order since uniq only keeps the first occurrence.
|
80
|
+
(obj1_keys + obj2_keys).uniq.each do |k|
|
81
|
+
if added_keys_lookup[k]
|
82
|
+
handle_key.call(k, :added)
|
83
|
+
elsif common_keys_lookup[k]
|
84
|
+
handle_key.call(k, :common)
|
85
|
+
elsif deleted_keys_lookup[k]
|
86
|
+
handle_key.call(k, :deleted)
|
87
|
+
end
|
64
88
|
end
|
89
|
+
else
|
90
|
+
# Keys are first grouped by operation type (deletions first, then changes, then additions), and then sorted
|
91
|
+
# alphabetically within each group.
|
92
|
+
deleted_keys.sort_by(&:to_s).each { |k| handle_key.call(k, :deleted) }
|
93
|
+
common_keys.sort_by(&:to_s).each { |k| handle_key.call(k, :common) }
|
94
|
+
added_keys.sort_by(&:to_s).each { |k| handle_key.call(k, :added) }
|
65
95
|
end
|
66
96
|
|
67
97
|
result
|
data/lib/hashdiff/diff.rb
CHANGED
@@ -9,13 +9,14 @@ module Hashdiff
|
|
9
9
|
# @param [Array, Hash] obj2
|
10
10
|
# @param [Hash] options the options to use when comparing
|
11
11
|
# * :strict (Boolean) [true] whether numeric values will be compared on type as well as value. Set to false to allow comparing Integer, Float, BigDecimal to each other
|
12
|
-
# * :ignore_keys (Symbol, String or Array) [[]] a list of keys to ignore. No comparison is made for the specified key(s)
|
12
|
+
# * :ignore_keys (Symbol, String or Array) [[]] a list of keys to ignore. No comparison is made for the specified key(s) in either hash
|
13
13
|
# * :indifferent (Boolean) [false] whether to treat hash keys indifferently. Set to true to ignore differences between symbol keys (ie. {a: 1} ~= {'a' => 1})
|
14
14
|
# * :delimiter (String) ['.'] the delimiter used when returning nested key references
|
15
15
|
# * :numeric_tolerance (Numeric) [0] should be a positive numeric value. Value by which numeric differences must be greater than. By default, numeric values are compared exactly; with the :tolerance option, the difference between numeric values must be greater than the given value.
|
16
16
|
# * :strip (Boolean) [false] whether or not to call #strip on strings before comparing
|
17
17
|
# * :array_path (Boolean) [false] whether to return the path references for nested values in an array, can be used for patch compatibility with non string keys.
|
18
18
|
# * :use_lcs (Boolean) [true] whether or not to use an implementation of the Longest common subsequence algorithm for comparing arrays, produces better diffs but is slower.
|
19
|
+
# * :preserve_key_order (Boolean) [false] If false, operations are grouped by type (-, ~, then +) then by hash key alphabetically. If true, preserves the original key order from the first hash and appends new keys from the second hash in order.
|
19
20
|
#
|
20
21
|
# @yield [path, value1, value2] Optional block is used to compare each value, instead of default #==. If the block returns value other than true of false, then other specified comparison options will be used to do the comparison.
|
21
22
|
#
|
@@ -54,7 +55,7 @@ module Hashdiff
|
|
54
55
|
# @param [Array, Hash] obj2
|
55
56
|
# @param [Hash] options the options to use when comparing
|
56
57
|
# * :strict (Boolean) [true] whether numeric values will be compared on type as well as value. Set to false to allow comparing Integer, Float, BigDecimal to each other
|
57
|
-
# * :ignore_keys (Symbol, String or Array) [[]] a list of keys to ignore. No comparison is made for the specified key(s)
|
58
|
+
# * :ignore_keys (Symbol, String or Array) [[]] a list of keys to ignore. No comparison is made for the specified key(s) in either hash
|
58
59
|
# * :indifferent (Boolean) [false] whether to treat hash keys indifferently. Set to true to ignore differences between symbol keys (ie. {a: 1} ~= {'a' => 1})
|
59
60
|
# * :similarity (Numeric) [0.8] should be between (0, 1]. Meaningful if there are similar hashes in arrays. See {best_diff}.
|
60
61
|
# * :delimiter (String) ['.'] the delimiter used when returning nested key references
|
@@ -62,6 +63,7 @@ module Hashdiff
|
|
62
63
|
# * :strip (Boolean) [false] whether or not to call #strip on strings before comparing
|
63
64
|
# * :array_path (Boolean) [false] whether to return the path references for nested values in an array, can be used for patch compatibility with non string keys.
|
64
65
|
# * :use_lcs (Boolean) [true] whether or not to use an implementation of the Longest common subsequence algorithm for comparing arrays, produces better diffs but is slower.
|
66
|
+
# * :preserve_key_order (Boolean) [false] If false, operations are grouped by type (-, ~, then +) then by hash key alphabetically. If true, preserves the original key order from the first hash and appends new keys from the second hash in order.
|
65
67
|
#
|
66
68
|
#
|
67
69
|
# @yield [path, value1, value2] Optional block is used to compare each value, instead of default #==. If the block returns value other than true of false, then other specified comparison options will be used to do the comparison.
|
@@ -88,12 +90,13 @@ module Hashdiff
|
|
88
90
|
strip: false,
|
89
91
|
numeric_tolerance: 0,
|
90
92
|
array_path: false,
|
91
|
-
use_lcs: true
|
93
|
+
use_lcs: true,
|
94
|
+
preserve_key_order: false
|
92
95
|
}.merge!(options)
|
93
96
|
|
94
97
|
opts[:prefix] = [] if opts[:array_path] && opts[:prefix] == ''
|
95
98
|
|
96
|
-
opts[:ignore_keys] = [*opts[:ignore_keys]]
|
99
|
+
opts[:ignore_keys] = [*opts[:ignore_keys]]
|
97
100
|
|
98
101
|
opts[:comparison] = block if block_given?
|
99
102
|
|
data/lib/hashdiff/version.rb
CHANGED
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: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Liu Fengyun
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-05-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bluecloth
|
@@ -88,6 +88,7 @@ executables: []
|
|
88
88
|
extensions: []
|
89
89
|
extra_rdoc_files: []
|
90
90
|
files:
|
91
|
+
- ".github/workflows/ci.yml"
|
91
92
|
- ".gitignore"
|
92
93
|
- ".rspec"
|
93
94
|
- ".rubocop.yml"
|
@@ -108,15 +109,6 @@ files:
|
|
108
109
|
- lib/hashdiff/patch.rb
|
109
110
|
- lib/hashdiff/util.rb
|
110
111
|
- lib/hashdiff/version.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/readme_spec.rb
|
118
|
-
- spec/hashdiff/util_spec.rb
|
119
|
-
- spec/spec_helper.rb
|
120
112
|
homepage: https://github.com/liufengyun/hashdiff
|
121
113
|
licenses:
|
122
114
|
- MIT
|
@@ -126,7 +118,7 @@ metadata:
|
|
126
118
|
documentation_uri: https://www.rubydoc.info/gems/hashdiff
|
127
119
|
homepage_uri: https://github.com/liufengyun/hashdiff
|
128
120
|
source_code_uri: https://github.com/liufengyun/hashdiff
|
129
|
-
post_install_message:
|
121
|
+
post_install_message:
|
130
122
|
rdoc_options: []
|
131
123
|
require_paths:
|
132
124
|
- lib
|
@@ -141,8 +133,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
141
133
|
- !ruby/object:Gem::Version
|
142
134
|
version: '0'
|
143
135
|
requirements: []
|
144
|
-
rubygems_version: 3.
|
145
|
-
signing_key:
|
136
|
+
rubygems_version: 3.3.5
|
137
|
+
signing_key:
|
146
138
|
specification_version: 4
|
147
139
|
summary: Hashdiff is a diff lib to compute the smallest difference between two hashes.
|
148
140
|
test_files: []
|
@@ -1,75 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'spec_helper'
|
4
|
-
|
5
|
-
describe Hashdiff do
|
6
|
-
it 'is able to best diff' do
|
7
|
-
a = { 'x' => [{ 'a' => 1, 'c' => 3, 'e' => 5 }, { 'y' => 3 }] }
|
8
|
-
b = { 'x' => [{ 'a' => 1, 'b' => 2, 'e' => 5 }] }
|
9
|
-
|
10
|
-
diff = described_class.best_diff(a, b)
|
11
|
-
diff.should == [['-', 'x[0].c', 3], ['+', 'x[0].b', 2], ['-', 'x[1]', { 'y' => 3 }]]
|
12
|
-
end
|
13
|
-
|
14
|
-
it 'uses custom delimiter when provided' do
|
15
|
-
a = { 'x' => [{ 'a' => 1, 'c' => 3, 'e' => 5 }, { 'y' => 3 }] }
|
16
|
-
b = { 'x' => [{ 'a' => 1, 'b' => 2, 'e' => 5 }] }
|
17
|
-
|
18
|
-
diff = described_class.best_diff(a, b, delimiter: "\t")
|
19
|
-
diff.should == [['-', "x[0]\tc", 3], ['+', "x[0]\tb", 2], ['-', 'x[1]', { 'y' => 3 }]]
|
20
|
-
end
|
21
|
-
|
22
|
-
it 'uses custom comparison when provided' do
|
23
|
-
a = { 'x' => [{ 'a' => 'foo', 'c' => 'goat', 'e' => 'snake' }, { 'y' => 'baz' }] }
|
24
|
-
b = { 'x' => [{ 'a' => 'bar', 'b' => 'cow', 'e' => 'puppy' }] }
|
25
|
-
|
26
|
-
diff = described_class.best_diff(a, b) do |path, obj1, obj2|
|
27
|
-
case path
|
28
|
-
when /^x\[.\]\..$/
|
29
|
-
obj1.length == obj2.length if obj1 && obj2
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
diff.should == [['-', 'x[0].c', 'goat'], ['+', 'x[0].b', 'cow'], ['-', 'x[1]', { 'y' => 'baz' }]]
|
34
|
-
end
|
35
|
-
|
36
|
-
it 'is able to best diff array in hash' do
|
37
|
-
a = { 'menu' => {
|
38
|
-
'id' => 'file',
|
39
|
-
'value' => 'File',
|
40
|
-
'popup' => {
|
41
|
-
'menuitem' => [
|
42
|
-
{ 'value' => 'New', 'onclick' => 'CreateNewDoc()' },
|
43
|
-
{ 'value' => 'Close', 'onclick' => 'CloseDoc()' }
|
44
|
-
]
|
45
|
-
}
|
46
|
-
} }
|
47
|
-
|
48
|
-
b = { 'menu' => {
|
49
|
-
'id' => 'file 2',
|
50
|
-
'value' => 'File',
|
51
|
-
'popup' => {
|
52
|
-
'menuitem' => [
|
53
|
-
{ 'value' => 'New1', 'onclick' => 'CreateNewDoc()' },
|
54
|
-
{ 'value' => 'Open', 'onclick' => 'OpenDoc()' },
|
55
|
-
{ 'value' => 'Close', 'onclick' => 'CloseDoc()' }
|
56
|
-
]
|
57
|
-
}
|
58
|
-
} }
|
59
|
-
|
60
|
-
diff = described_class.best_diff(a, b)
|
61
|
-
diff.should == [
|
62
|
-
['~', 'menu.id', 'file', 'file 2'],
|
63
|
-
['~', 'menu.popup.menuitem[0].value', 'New', 'New1'],
|
64
|
-
['+', 'menu.popup.menuitem[1]', { 'value' => 'Open', 'onclick' => 'OpenDoc()' }]
|
65
|
-
]
|
66
|
-
end
|
67
|
-
|
68
|
-
it 'is able to have an array_path specified' do
|
69
|
-
a = { 'x' => [{ 'a' => 1, 'c' => 3, 'e' => 5 }, { 'y' => 3 }] }
|
70
|
-
b = { 'x' => [{ 'a' => 1, 'b' => 2, 'e' => 5 }] }
|
71
|
-
|
72
|
-
diff = described_class.best_diff(a, b, array_path: true)
|
73
|
-
diff.should == [['-', ['x', 0, 'c'], 3], ['+', ['x', 0, 'b'], 2], ['-', ['x', 1], { 'y' => 3 }]]
|
74
|
-
end
|
75
|
-
end
|
@@ -1,60 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'spec_helper'
|
4
|
-
|
5
|
-
describe Hashdiff do
|
6
|
-
it 'is able to diff two equal array' do
|
7
|
-
a = [1, 2, 3]
|
8
|
-
b = [1, 2, 3]
|
9
|
-
|
10
|
-
diff = described_class.diff_array_lcs(a, b)
|
11
|
-
diff.should == []
|
12
|
-
end
|
13
|
-
|
14
|
-
it 'is able to diff two arrays with one element in common' do
|
15
|
-
a = [1, 2, 3]
|
16
|
-
b = [1, 8, 7]
|
17
|
-
|
18
|
-
diff = described_class.diff_array_lcs(a, b)
|
19
|
-
diff.should == [['-', 2, 3], ['-', 1, 2], ['+', 1, 8], ['+', 2, 7]]
|
20
|
-
end
|
21
|
-
|
22
|
-
it 'is able to diff two arrays with nothing in common' do
|
23
|
-
a = [1, 2]
|
24
|
-
b = []
|
25
|
-
|
26
|
-
diff = described_class.diff_array_lcs(a, b)
|
27
|
-
diff.should == [['-', 1, 2], ['-', 0, 1]]
|
28
|
-
end
|
29
|
-
|
30
|
-
it 'is able to diff an empty array with an non-empty array' do
|
31
|
-
a = []
|
32
|
-
b = [1, 2]
|
33
|
-
|
34
|
-
diff = described_class.diff_array_lcs(a, b)
|
35
|
-
diff.should == [['+', 0, 1], ['+', 1, 2]]
|
36
|
-
end
|
37
|
-
|
38
|
-
it 'is able to diff two arrays with two elements in common' do
|
39
|
-
a = [1, 3, 5, 7]
|
40
|
-
b = [2, 3, 7, 5]
|
41
|
-
|
42
|
-
diff = described_class.diff_array_lcs(a, b)
|
43
|
-
diff.should == [['-', 0, 1], ['+', 0, 2], ['+', 2, 7], ['-', 4, 7]]
|
44
|
-
end
|
45
|
-
|
46
|
-
it 'is able to test two arrays with two common elements in different order' do
|
47
|
-
a = [1, 3, 4, 7]
|
48
|
-
b = [2, 3, 7, 5]
|
49
|
-
|
50
|
-
diff = described_class.diff_array_lcs(a, b)
|
51
|
-
diff.should == [['-', 0, 1], ['+', 0, 2], ['-', 2, 4], ['+', 3, 5]]
|
52
|
-
end
|
53
|
-
|
54
|
-
it 'is able to diff two arrays with similar elements' do
|
55
|
-
a = [{ 'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5 }, 3]
|
56
|
-
b = [1, { 'a' => 1, 'b' => 2, 'c' => 3, 'e' => 5 }]
|
57
|
-
diff = described_class.diff_array_lcs(a, b)
|
58
|
-
diff.should == [['+', 0, 1], ['-', 2, 3]]
|
59
|
-
end
|
60
|
-
end
|