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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 56a70b8fb995b7d778a1840400c42303c34648a9205055b11157a5b69208afa1
4
- data.tar.gz: 410e1bea7bc27e43f4580c42ff17054e1ce57dc3c3f486fe570269e366c7ecb4
3
+ metadata.gz: 4752d45ff706f5b763bb7bc2b6b6c4302657caad5e45fce2d02730d962ef3d31
4
+ data.tar.gz: 5d9ff9c909184d3bbd798a3dbc8ea82d1c2752450c0c04671755aaa0d8d34c25
5
5
  SHA512:
6
- metadata.gz: 30e90e14ee676c7b035a20d01f5f8cf5dfcdae7319f652bd828c6fcc8d66a4e6b0cb8fd046937ce09a38aac8e7c3eba92dfc60b8ea2e09674eb9c8ea35256e9a
7
- data.tar.gz: 146cc4564d22ee6c6ef47b09032e4e171cd2682ecd941e798bd729bea7d3e8a10974356e39500886bd6ec4d0d3d6c109d2e6556bbe47abc7b79a9c9d45db66e4
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
- Metrics/LineLength:
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/FilePath:
39
+ RSpec/SpecFilePathFormat:
40
+ Enabled: false
41
+ RSpec/NoExpectationExample:
40
42
  Enabled: false
data/README.md CHANGED
@@ -1,4 +1,4 @@
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://github.com/liufengyun/hashdiff/workflows/ci/badge.svg)](https://github.com/liufengyun/hashdiff/actions?query=workflow%3Aci) [![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
 
@@ -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` and `:use_lcs`
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: 1, b: { d: 2, a: 3 }, c: 4 }
126
- b = { a: 2, b: { d: 2, a: 7 }, c: 5 }
127
- diff = Hashdiff.diff(a, b, ignore_keys: :a)
128
- diff.should == [['~', 'c', 4, 5]]
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: 1, b: { d: 2, a: 3 }, c: 4 }
135
- b = { a: 2, b: { d: 2, a: 7 }, c: 5 }
136
- diff = Hashdiff.diff(a, b) { |path, _e, _a| true if path == 'b.a' } # note '.' is the default delimiter
137
- diff.should == [['~', 'a', 1, 2], ['~', 'c', 4, 5]]
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.1.0 2020-02-25
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 = (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)
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 { |k| common_keys.delete k }
30
-
31
- # add deleted properties
32
- deleted_keys.each do |k|
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
- # recursive comparison for common keys
45
- common_keys.each do |k|
46
- prefix = Hashdiff.prefix_append_key(opts[:prefix], k, opts)
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
- k1 = opts[:indifferent] ? obj1_lookup[k] : k
49
- k2 = opts[:indifferent] ? obj2_lookup[k] : k
50
- result.concat(Hashdiff.diff(obj1[k1], obj2[k2], opts.merge(prefix: prefix)))
51
- end
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
- # added properties
54
- added_keys.each do |k|
55
- change_key = Hashdiff.prefix_append_key(opts[:prefix], k, opts)
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
- k = opts[:indifferent] ? obj2_lookup[k] : k
58
- custom_result = Hashdiff.custom_compare(opts[:comparison], change_key, nil, obj2[k])
59
+ k = opts[:indifferent] ? obj2_lookup[k] : k
60
+ custom_result = Hashdiff.custom_compare(opts[:comparison], change_key, nil, obj2[k])
59
61
 
60
- if custom_result
61
- result.concat(custom_result)
62
+ if custom_result
63
+ result.concat(custom_result)
64
+ else
65
+ result << ['+', change_key, obj2[k]]
66
+ end
62
67
  else
63
- result << ['+', change_key, obj2[k]]
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]] # splat covers single sym/string case
99
+ opts[:ignore_keys] = [*opts[:ignore_keys]]
97
100
 
98
101
  opts[:comparison] = block if block_given?
99
102
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Hashdiff
4
- VERSION = '1.1.0'.freeze
4
+ VERSION = '1.2.0'.freeze
5
5
  end
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.1.0
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: 2023-12-14 00:00:00.000000000 Z
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.4.10
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