hashdiff 1.1.0 → 1.1.1

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
  SHA256:
3
- metadata.gz: 56a70b8fb995b7d778a1840400c42303c34648a9205055b11157a5b69208afa1
4
- data.tar.gz: 410e1bea7bc27e43f4580c42ff17054e1ce57dc3c3f486fe570269e366c7ecb4
3
+ metadata.gz: c563bf8c756695c81b5c7ab98a90e59ebdff506544fff2b53c3d93eafff7dc44
4
+ data.tar.gz: 188a825aaf4f09fb2055fc8ccd34a1904171f0b10cb3e3b2cfd55e9cc096fdc3
5
5
  SHA512:
6
- metadata.gz: 30e90e14ee676c7b035a20d01f5f8cf5dfcdae7319f652bd828c6fcc8d66a4e6b0cb8fd046937ce09a38aac8e7c3eba92dfc60b8ea2e09674eb9c8ea35256e9a
7
- data.tar.gz: 146cc4564d22ee6c6ef47b09032e4e171cd2682ecd941e798bd729bea7d3e8a10974356e39500886bd6ec4d0d3d6c109d2e6556bbe47abc7b79a9c9d45db66e4
6
+ metadata.gz: be6a233462744f5b7eecea33d0487455ecc4a1b178ea361187ef023bb49d4f609c991689fdb48309694bb5582475d06f21530842a728dc9ab720aa6a0352b54b
7
+ data.tar.gz: 1126790d1eb87fe3c314bc2360f92f224e88412acf09ed10d964902466e3218c50c68a66972b63d6d92f7963b62001b336b3b5b362eb3ad9a2e50472c66f45b1
@@ -0,0 +1,28 @@
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
+ - name: Install dependencies
26
+ run: bundle install --jobs $(nproc) --retry 3
27
+ - name: Run rake
28
+ 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
 
@@ -119,23 +119,26 @@ The `:strict` option, which defaults to `true`, specifies whether numeric types
119
119
 
120
120
  #### `:ignore_keys`
121
121
 
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:
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 in both hashes. For example:
123
123
 
124
124
  ```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]]
125
+ a = { a: 4, g: 0, b: { a: 5, c: 6, e: 1 } }
126
+ b = { b: { a: 7, c: 3, f: 1 }, d: 8 }
127
+ diff = Hashdiff.diff(a, b, ignore_keys: %i[a f])
128
+ diff.should == [['-', 'g', 0], ['-', 'b.e', 1], ['~', 'b.c', 6, 3], ['+', 'd', 8]]
129
129
  ```
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:
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 to diff only at the 2nd level of both hashes:
132
132
 
133
133
  ```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
- ```
134
+ a = { a: 4, g: 0, b: { a: 5, c: 6, e: 1 } }
135
+ b = { b: { a: 7, c: 3, f: 1 }, d: 8 }
136
+ diff = Hashdiff.diff(a, b) do |path, _e, _a|
137
+ arr = path.split('.')
138
+ true if %w[a f].include?(arr.last) && arr.size == 2 # note '.' is the default delimiter
139
+ end
140
+ diff.should == [['-', 'a', 4], ['-', 'g', 0], ['-', 'b.e', 1], ['~', 'b.c', 6, 3], ['+', 'd', 8]]
141
+ ```
139
142
 
140
143
  #### `:indifferent`
141
144
 
data/changelog.md CHANGED
@@ -1,6 +1,11 @@
1
1
  # Change Log
2
2
 
3
- ## v1.1.0 2020-02-25
3
+ ## v1.1.1 2024-08-02
4
+
5
+ * Fix bug in ignore_keys option #88 (@Matzfan)
6
+ * Exclude spec files from gem package #94 (@amatsuda)
7
+
8
+ ## v1.1.0 2023-12-14
4
9
 
5
10
  * Add ignore_keys option (#86 @Matzfan)
6
11
  * 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']
@@ -26,7 +26,11 @@ module Hashdiff
26
26
 
27
27
  result = []
28
28
 
29
- opts[:ignore_keys].each { |k| common_keys.delete k }
29
+ opts[:ignore_keys].each do |k|
30
+ added_keys.delete k
31
+ common_keys.delete k
32
+ deleted_keys.delete k
33
+ end
30
34
 
31
35
  # add deleted properties
32
36
  deleted_keys.each do |k|
data/lib/hashdiff/diff.rb CHANGED
@@ -9,7 +9,7 @@ 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.
@@ -54,7 +54,7 @@ module Hashdiff
54
54
  # @param [Array, Hash] obj2
55
55
  # @param [Hash] options the options to use when comparing
56
56
  # * :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)
57
+ # * :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
58
  # * :indifferent (Boolean) [false] whether to treat hash keys indifferently. Set to true to ignore differences between symbol keys (ie. {a: 1} ~= {'a' => 1})
59
59
  # * :similarity (Numeric) [0.8] should be between (0, 1]. Meaningful if there are similar hashes in arrays. See {best_diff}.
60
60
  # * :delimiter (String) ['.'] the delimiter used when returning nested key references
@@ -93,7 +93,7 @@ module Hashdiff
93
93
 
94
94
  opts[:prefix] = [] if opts[:array_path] && opts[:prefix] == ''
95
95
 
96
- opts[:ignore_keys] = [*opts[:ignore_keys]] # splat covers single sym/string case
96
+ opts[:ignore_keys] = [*opts[:ignore_keys]]
97
97
 
98
98
  opts[:comparison] = block if block_given?
99
99
 
@@ -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.1.1'.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.1.1
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: 2024-08-02 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
@@ -1,375 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- describe Hashdiff do
6
- it 'is able to diff two empty hashes' do
7
- diff = described_class.diff({}, {})
8
- diff.should == []
9
- end
10
-
11
- it 'is able to diff an hash with an empty hash' do
12
- a = { 'a' => 3, 'b' => 2 }
13
- b = {}
14
-
15
- diff = described_class.diff(a, b)
16
- expect(diff).to eq([['-', 'a', 3], ['-', 'b', 2]])
17
-
18
- diff = described_class.diff(b, a)
19
- diff.should == [['+', 'a', 3], ['+', 'b', 2]]
20
- end
21
-
22
- it 'is able to diff two equal hashes' do
23
- diff = described_class.diff({ 'a' => 2, 'b' => 2 }, 'a' => 2, 'b' => 2)
24
- diff.should == []
25
- end
26
-
27
- it 'is able to diff two equal hashes with mixed key types' do
28
- a = { 'a' => 1, :b => 1 }
29
- diff = described_class.diff(a, a)
30
- diff.should == []
31
- end
32
-
33
- it 'is able to diff if mixed key types are removed' do
34
- a = { 'a' => 1, :b => 1 }
35
- b = {}
36
- diff = described_class.diff(a, b)
37
- diff.should == [['-', 'a', 1], ['-', 'b', 1]]
38
- end
39
-
40
- it 'is able to diff if mixed key types are added' do
41
- a = { 'a' => 1, :b => 1 }
42
- b = {}
43
- diff = described_class.diff(b, a)
44
- diff.should == [['+', 'a', 1], ['+', 'b', 1]]
45
- end
46
-
47
- it 'is able to diff two hashes with equivalent numerics, when strict is false' do
48
- diff = described_class.diff({ 'a' => 2.0, 'b' => 2 }, { 'a' => 2, 'b' => 2.0 }, strict: false)
49
- diff.should == []
50
- end
51
-
52
- context 'with the ignore_keys option' do
53
- a = { a: 1, b: { d: 2, a: 3 }, c: 4 }
54
- b = { a: 2, b: { d: 2, a: 7 }, c: 5 }
55
-
56
- it 'ignores a single key' do
57
- diff = described_class.diff(a, b, ignore_keys: :a)
58
- diff.should == [['~', 'c', 4, 5]]
59
- end
60
-
61
- it 'ignores an array of keys' do
62
- diff = described_class.diff(a, b, ignore_keys: %i[a c])
63
- diff.should == []
64
- end
65
- end
66
-
67
- it 'ignores string vs symbol differences, when indifferent is true' do
68
- diff = described_class.diff({ 'a' => 2, :b => 2 }, { :a => 2, 'b' => 2, :c => 3 }, indifferent: true)
69
- diff.should == [['+', 'c', 3]]
70
- end
71
-
72
- it 'is able to diff changes in hash value' do
73
- diff = described_class.diff({ 'a' => 2, 'b' => 3, 'c' => ' hello' }, 'a' => 2, 'b' => 4, 'c' => 'hello')
74
- diff.should == [['~', 'b', 3, 4], ['~', 'c', ' hello', 'hello']]
75
- end
76
-
77
- it 'is able to diff changes in hash value which is array' do
78
- diff = described_class.diff({ 'a' => 2, 'b' => [1, 2, 3] }, 'a' => 2, 'b' => [1, 3, 4])
79
- diff.should == [['-', 'b[1]', 2], ['+', 'b[2]', 4]]
80
- end
81
-
82
- it 'is able to diff changes in hash value which is hash' do
83
- diff = described_class.diff({ 'a' => { 'x' => 2, 'y' => 3, 'z' => 4 }, 'b' => { 'x' => 3, 'z' => 45 } },
84
- 'a' => { 'y' => 3 }, 'b' => { 'y' => 3, 'z' => 30 })
85
- diff.should == [['-', 'a.x', 2], ['-', 'a.z', 4], ['-', 'b.x', 3], ['~', 'b.z', 45, 30], ['+', 'b.y', 3]]
86
- end
87
-
88
- it 'is able to best diff similar objects in array' do
89
- diff = described_class.best_diff({ 'a' => [{ 'x' => 2, 'y' => 3, 'z' => 4 }, { 'x' => 11, 'y' => 22, 'z' => 33 }], 'b' => { 'x' => 3, 'z' => 45 } },
90
- 'a' => [{ 'y' => 3 }, { 'x' => 11, 'z' => 33 }], 'b' => { 'y' => 22 })
91
- diff.should == [['-', 'a[0].x', 2], ['-', 'a[0].z', 4], ['-', 'a[1].y', 22], ['-', 'b.x', 3], ['-', 'b.z', 45], ['+', 'b.y', 22]]
92
- end
93
-
94
- it 'is able to diff addition of key value pair' do
95
- a = { 'a' => 3, 'c' => 11, 'd' => 45, 'e' => 100, 'f' => 200 }
96
- b = { 'a' => 3, 'c' => 11, 'd' => 45, 'e' => 100, 'f' => 200, 'g' => 300 }
97
-
98
- diff = described_class.diff(a, b)
99
- expect(diff).to eq([['+', 'g', 300]])
100
-
101
- diff = described_class.diff(b, a)
102
- diff.should == [['-', 'g', 300]]
103
- end
104
-
105
- it 'is able to diff value type changes' do
106
- a = { 'a' => 3 }
107
- b = { 'a' => { 'a1' => 1, 'a2' => 2 } }
108
-
109
- diff = described_class.diff(a, b)
110
- expect(diff).to eq([['~', 'a', 3, { 'a1' => 1, 'a2' => 2 }]])
111
-
112
- diff = described_class.diff(b, a)
113
- diff.should == [['~', 'a', { 'a1' => 1, 'a2' => 2 }, 3]]
114
- end
115
-
116
- it 'is able to diff value changes: array <=> []' do
117
- a = { 'a' => 1, 'b' => [1, 2] }
118
- b = { 'a' => 1, 'b' => [] }
119
-
120
- diff = described_class.diff(a, b)
121
- diff.should == [['-', 'b[1]', 2], ['-', 'b[0]', 1]]
122
- end
123
-
124
- it 'is able to diff value changes: array <=> nil' do
125
- a = { 'a' => 1, 'b' => [1, 2] }
126
- b = { 'a' => 1, 'b' => nil }
127
-
128
- diff = described_class.diff(a, b)
129
- diff.should == [['~', 'b', [1, 2], nil]]
130
- end
131
-
132
- it 'is able to diff value chagnes: remove array completely' do
133
- a = { 'a' => 1, 'b' => [1, 2] }
134
- b = { 'a' => 1 }
135
-
136
- diff = described_class.diff(a, b)
137
- diff.should == [['-', 'b', [1, 2]]]
138
- end
139
-
140
- it 'is able to diff value changes: remove whole hash' do
141
- a = { 'a' => 1, 'b' => { 'b1' => 1, 'b2' => 2 } }
142
- b = { 'a' => 1 }
143
-
144
- diff = described_class.diff(a, b)
145
- diff.should == [['-', 'b', { 'b1' => 1, 'b2' => 2 }]]
146
- end
147
-
148
- it 'is able to diff value changes: hash <=> {}' do
149
- a = { 'a' => 1, 'b' => { 'b1' => 1, 'b2' => 2 } }
150
- b = { 'a' => 1, 'b' => {} }
151
-
152
- diff = described_class.diff(a, b)
153
- diff.should == [['-', 'b.b1', 1], ['-', 'b.b2', 2]]
154
- end
155
-
156
- it 'is able to diff value changes: hash <=> nil' do
157
- a = { 'a' => 1, 'b' => { 'b1' => 1, 'b2' => 2 } }
158
- b = { 'a' => 1, 'b' => nil }
159
-
160
- diff = described_class.diff(a, b)
161
- diff.should == [['~', 'b', { 'b1' => 1, 'b2' => 2 }, nil]]
162
- end
163
-
164
- it 'is able to diff similar objects in array' do
165
- a = [{ 'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5 }, 3]
166
- b = [1, { 'a' => 1, 'b' => 2, 'c' => 3, 'e' => 5 }]
167
-
168
- diff = described_class.diff(a, b)
169
- diff.should == [['-', '[0].d', 4], ['+', '[0]', 1], ['-', '[2]', 3]]
170
- end
171
-
172
- it 'is able to diff similar & equal objects in array' do
173
- a = [{ 'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5 }, { 'x' => 5, 'y' => 6, 'z' => 3 }, 3]
174
- b = [{ 'a' => 1, 'b' => 2, 'c' => 3, 'e' => 5 }, 3]
175
-
176
- diff = described_class.diff(a, b)
177
- diff.should == [['-', '[0].d', 4], ['-', '[1]', { 'x' => 5, 'y' => 6, 'z' => 3 }]]
178
- end
179
-
180
- it 'uses custom delimiter when provided' do
181
- a = [{ 'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5 }, { 'x' => 5, 'y' => 6, 'z' => 3 }, 3]
182
- b = [{ 'a' => 1, 'b' => 2, 'c' => 3, 'e' => 5 }, 3]
183
-
184
- diff = described_class.diff(a, b, similarity: 0.8, delimiter: "\t")
185
- diff.should == [['-', "[0]\td", 4], ['-', '[1]', { 'x' => 5, 'y' => 6, 'z' => 3 }]]
186
- end
187
-
188
- context 'when :numeric_tolerance requested' do
189
- it 'is able to diff changes in hash value' do
190
- a = { 'a' => 0.558, 'b' => 0.0, 'c' => 0.65, 'd' => 'fin' }
191
- b = { 'a' => 0.557, 'b' => 'hats', 'c' => 0.67, 'd' => 'fin' }
192
-
193
- diff = described_class.diff(a, b, numeric_tolerance: 0.01)
194
- expect(diff).to eq([['~', 'b', 0.0, 'hats'], ['~', 'c', 0.65, 0.67]])
195
-
196
- diff = described_class.diff(b, a, numeric_tolerance: 0.01)
197
- diff.should == [['~', 'b', 'hats', 0.0], ['~', 'c', 0.67, 0.65]]
198
- end
199
-
200
- it 'is able to diff changes in nested values' do
201
- a = { 'a' => { 'x' => 0.4, 'y' => 0.338 }, 'b' => [13, 68.03] }
202
- b = { 'a' => { 'x' => 0.6, 'y' => 0.341 }, 'b' => [14, 68.025] }
203
-
204
- diff = described_class.diff(a, b, numeric_tolerance: 0.01)
205
- expect(diff).to eq([['~', 'a.x', 0.4, 0.6], ['-', 'b[0]', 13], ['+', 'b[0]', 14]])
206
-
207
- diff = described_class.diff(b, a, numeric_tolerance: 0.01)
208
- diff.should == [['~', 'a.x', 0.6, 0.4], ['-', 'b[0]', 14], ['+', 'b[0]', 13]]
209
- end
210
- end
211
-
212
- context 'when :strip requested' do
213
- it 'strips strings before comparing' do
214
- a = { 'a' => ' foo', 'b' => 'fizz buzz' }
215
- b = { 'a' => 'foo', 'b' => 'fizzbuzz' }
216
- diff = described_class.diff(a, b, strip: true)
217
- diff.should == [['~', 'b', 'fizz buzz', 'fizzbuzz']]
218
- end
219
-
220
- it 'strips nested strings before comparing' do
221
- a = { 'a' => { 'x' => ' foo' }, 'b' => ['fizz buzz', 'nerf'] }
222
- b = { 'a' => { 'x' => 'foo' }, 'b' => %w[fizzbuzz nerf] }
223
- diff = described_class.diff(a, b, strip: true)
224
- diff.should == [['-', 'b[0]', 'fizz buzz'], ['+', 'b[0]', 'fizzbuzz']]
225
- end
226
- end
227
-
228
- context 'when :case_insensitive requested' do
229
- it 'strips strings before comparing' do
230
- a = { 'a' => 'Foo', 'b' => 'fizz buzz' }
231
- b = { 'a' => 'foo', 'b' => 'fizzBuzz' }
232
- diff = described_class.diff(a, b, case_insensitive: true)
233
- diff.should == [['~', 'b', 'fizz buzz', 'fizzBuzz']]
234
- end
235
-
236
- it 'ignores case on nested strings before comparing' do
237
- a = { 'a' => { 'x' => 'Foo' }, 'b' => ['fizz buzz', 'nerf'] }
238
- b = { 'a' => { 'x' => 'foo' }, 'b' => %w[fizzbuzz nerf] }
239
- diff = described_class.diff(a, b, case_insensitive: true)
240
- diff.should == [['-', 'b[0]', 'fizz buzz'], ['+', 'b[0]', 'fizzbuzz']]
241
- end
242
- end
243
-
244
- context 'when both :strip and :numeric_tolerance requested' do
245
- it 'applies filters to proper object types' do
246
- a = { 'a' => ' foo', 'b' => 35, 'c' => 'bar', 'd' => 'baz' }
247
- b = { 'a' => 'foo', 'b' => 35.005, 'c' => 'bar', 'd' => 18.5 }
248
- diff = described_class.diff(a, b, strict: false, numeric_tolerance: 0.01, strip: true)
249
- diff.should == [['~', 'd', 'baz', 18.5]]
250
- end
251
- end
252
-
253
- context 'when both :strip and :case_insensitive requested' do
254
- it 'applies both filters to strings' do
255
- a = { 'a' => ' Foo', 'b' => 'fizz buzz' }
256
- b = { 'a' => 'foo', 'b' => 'fizzBuzz' }
257
- diff = described_class.diff(a, b, case_insensitive: true, strip: true)
258
- diff.should == [['~', 'b', 'fizz buzz', 'fizzBuzz']]
259
- end
260
- end
261
-
262
- context 'with custom comparison' do
263
- let(:a) { { 'a' => 'car', 'b' => 'boat', 'c' => 'plane' } }
264
- let(:b) { { 'a' => 'bus', 'b' => 'truck', 'c' => ' plan' } }
265
-
266
- it 'compares using proc specified in block' do
267
- diff = described_class.diff(a, b) do |prefix, obj1, obj2|
268
- case prefix
269
- when /a|b|c/
270
- obj1.length == obj2.length
271
- end
272
- end
273
- diff.should == [['~', 'b', 'boat', 'truck']]
274
- end
275
-
276
- it 'yields added keys' do
277
- x = { 'a' => 'car', 'b' => 'boat' }
278
- y = { 'a' => 'car' }
279
-
280
- diff = described_class.diff(x, y) do |prefix, _obj1, _obj2|
281
- case prefix
282
- when /b/
283
- true
284
- end
285
- end
286
- diff.should == []
287
- end
288
-
289
- it 'compares with both proc and :strip when both provided' do
290
- diff = described_class.diff(a, b, strip: true) do |prefix, obj1, obj2|
291
- case prefix
292
- when 'a'
293
- obj1.length == obj2.length
294
- end
295
- end
296
- diff.should == [['~', 'b', 'boat', 'truck'], ['~', 'c', 'plane', ' plan']]
297
- end
298
-
299
- it 'compares nested arrays using proc specified in block' do
300
- a = { a: 'car', b: %w[boat plane] }
301
- b = { a: 'bus', b: ['truck', ' plan'] }
302
-
303
- diff = described_class.diff(a, b) do |path, obj1, obj2|
304
- case path
305
- when 'b[*]'
306
- obj1.length == obj2.length
307
- end
308
- end
309
-
310
- expect(diff).to eq [['~', 'a', 'car', 'bus'], ['~', 'b[1]', 'plane', ' plan'], ['-', 'b[0]', 'boat'], ['+', 'b[0]', 'truck']]
311
- end
312
- end
313
-
314
- context 'when :array_path is true' do
315
- it 'returns the diff path in an array rather than a string' do
316
- x = { 'a' => 'foo' }
317
- y = { 'a' => 'bar' }
318
- diff = described_class.diff(x, y, array_path: true)
319
-
320
- diff.should == [['~', ['a'], 'foo', 'bar']]
321
- end
322
-
323
- it 'shows array indexes in paths' do
324
- x = { 'a' => [0, 1, 2] }
325
- y = { 'a' => [0, 1, 2, 3] }
326
-
327
- diff = described_class.diff(x, y, array_path: true)
328
-
329
- diff.should == [['+', ['a', 3], 3]]
330
- end
331
-
332
- it 'shows differences with string and symbol keys' do
333
- x = { 'a' => 'foo' }
334
- y = { a: 'bar' }
335
-
336
- diff = described_class.diff(x, y, array_path: true)
337
- diff.should == [['-', ['a'], 'foo'], ['+', [:a], 'bar']]
338
- end
339
-
340
- it 'supports other key types' do
341
- time = Time.now
342
- x = { time => 'foo' }
343
- y = { 0 => 'bar' }
344
-
345
- diff = described_class.diff(x, y, array_path: true)
346
- diff.should == [['-', [time], 'foo'], ['+', [0], 'bar']]
347
- end
348
- end
349
-
350
- context 'when :use_lcs is false' do
351
- it 'shows items in an array as changed' do
352
- x = %i[a b]
353
- y = %i[c d]
354
- diff = described_class.diff(x, y, use_lcs: false)
355
-
356
- diff.should == [['~', '[0]', :a, :c], ['~', '[1]', :b, :d]]
357
- end
358
-
359
- it 'shows additions to arrays' do
360
- x = { a: [0] }
361
- y = { a: [0, 1] }
362
- diff = described_class.diff(x, y, use_lcs: false)
363
-
364
- diff.should == [['+', 'a[1]', 1]]
365
- end
366
-
367
- it 'shows changes to nested arrays' do
368
- x = { a: [[0, 1]] }
369
- y = { a: [[1, 2]] }
370
- diff = described_class.diff(x, y, use_lcs: false)
371
-
372
- diff.should == [['~', 'a[0][0]', 0, 1], ['~', 'a[0][1]', 1, 2]]
373
- end
374
- end
375
- end
@@ -1,76 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- describe Hashdiff do
6
- it 'is able to find LCS between two equal array' do
7
- a = [1, 2, 3]
8
- b = [1, 2, 3]
9
-
10
- lcs = described_class.lcs(a, b)
11
- lcs.should == [[0, 0], [1, 1], [2, 2]]
12
- end
13
-
14
- it 'is able to find LCS between two close arrays' do
15
- a = [1.05, 2, 3.25]
16
- b = [1.06, 2, 3.24]
17
-
18
- lcs = described_class.lcs(a, b, numeric_tolerance: 0.1)
19
- lcs.should == [[0, 0], [1, 1], [2, 2]]
20
- end
21
-
22
- it 'strips strings when finding LCS if requested' do
23
- a = %w[foo bar baz]
24
- b = [' foo', 'bar', 'zab']
25
-
26
- lcs = described_class.lcs(a, b, strip: true)
27
- lcs.should == [[0, 0], [1, 1]]
28
- end
29
-
30
- it 'is able to find LCS with one common elements' do
31
- a = [1, 2, 3]
32
- b = [1, 8, 7]
33
-
34
- lcs = described_class.lcs(a, b)
35
- lcs.should == [[0, 0]]
36
- end
37
-
38
- it 'is able to find LCS with two common elements' do
39
- a = [1, 3, 5, 7]
40
- b = [2, 3, 7, 5]
41
-
42
- lcs = described_class.lcs(a, b)
43
- lcs.should == [[1, 1], [2, 3]]
44
- end
45
-
46
- it 'is able to find LCS with two close elements' do
47
- a = [1, 3.05, 5, 7]
48
- b = [2, 3.06, 7, 5]
49
-
50
- lcs = described_class.lcs(a, b, numeric_tolerance: 0.1)
51
- lcs.should == [[1, 1], [2, 3]]
52
- end
53
-
54
- it 'is able to find LCS with two common elements in different ordering' do
55
- a = [1, 3, 4, 7]
56
- b = [2, 3, 7, 5]
57
-
58
- lcs = described_class.lcs(a, b)
59
- lcs.should == [[1, 1], [3, 2]]
60
- end
61
-
62
- it 'is able to find LCS with a similarity value' do
63
- a = [
64
- { 'value' => 'New', 'onclick' => 'CreateNewDoc()' },
65
- { 'value' => 'Close', 'onclick' => 'CloseDoc()' }
66
- ]
67
- b = [
68
- { 'value' => 'New1', 'onclick' => 'CreateNewDoc()' },
69
- { 'value' => 'Open', 'onclick' => 'OpenDoc()' },
70
- { 'value' => 'Close', 'onclick' => 'CloseDoc()' }
71
- ]
72
-
73
- lcs = described_class.lcs(a, b, similarity: 0.5)
74
- lcs.should == [[0, 0], [1, 2]]
75
- end
76
- end
@@ -1,50 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- describe Hashdiff::LinearCompareArray do
6
- it 'finds no differences between two empty arrays' do
7
- difference = described_class.call([], [])
8
- difference.should == []
9
- end
10
-
11
- it 'finds added items when the old array is empty' do
12
- difference = described_class.call([], %i[a b])
13
- difference.should == [['+', '[0]', :a], ['+', '[1]', :b]]
14
- end
15
-
16
- it 'finds removed items when the new array is empty' do
17
- difference = described_class.call(%i[a b], [])
18
- difference.should == [['-', '[1]', :b], ['-', '[0]', :a]]
19
- end
20
-
21
- it 'finds no differences between identical arrays' do
22
- difference = described_class.call(%i[a b], %i[a b])
23
- difference.should == []
24
- end
25
-
26
- it 'finds added items in an array' do
27
- difference = described_class.call(%i[a d], %i[a b c d])
28
- difference.should == [['+', '[1]', :b], ['+', '[2]', :c]]
29
- end
30
-
31
- it 'finds removed items in an array' do
32
- difference = described_class.call(%i[a b c d e f], %i[a d f])
33
- difference.should == [['-', '[4]', :e], ['-', '[2]', :c], ['-', '[1]', :b]]
34
- end
35
-
36
- it 'shows additions and deletions as changed items' do
37
- difference = described_class.call(%i[a b c], %i[c b a])
38
- difference.should == [['~', '[0]', :a, :c], ['~', '[2]', :c, :a]]
39
- end
40
-
41
- it 'shows changed items in a hash' do
42
- difference = described_class.call([{ a: :b }], [{ a: :c }])
43
- difference.should == [['~', '[0].a', :b, :c]]
44
- end
45
-
46
- it 'shows changed items and added items' do
47
- difference = described_class.call([{ a: 1, b: 2 }], [{ a: 2, b: 2 }, :item])
48
- difference.should == [['~', '[0].a', 1, 2], ['+', '[1]', :item]]
49
- end
50
- end
@@ -1,185 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- describe Hashdiff do
6
- it 'is able to patch key addition' do
7
- a = { 'a' => 3, 'c' => 11, 'd' => 45, 'e' => 100, 'f' => 200 }
8
- b = { 'a' => 3, 'c' => 11, 'd' => 45, 'e' => 100, 'f' => 200, 'g' => 300 }
9
- diff = described_class.diff(a, b)
10
-
11
- expect(described_class.patch!(a, diff)).to eq(b)
12
-
13
- a = { 'a' => 3, 'c' => 11, 'd' => 45, 'e' => 100, 'f' => 200 }
14
- b = { 'a' => 3, 'c' => 11, 'd' => 45, 'e' => 100, 'f' => 200, 'g' => 300 }
15
- described_class.unpatch!(b, diff).should == a
16
- end
17
-
18
- it 'is able to patch value type changes' do
19
- a = { 'a' => 3 }
20
- b = { 'a' => { 'a1' => 1, 'a2' => 2 } }
21
- diff = described_class.diff(a, b)
22
-
23
- expect(described_class.patch!(a, diff)).to eq(b)
24
-
25
- a = { 'a' => 3 }
26
- b = { 'a' => { 'a1' => 1, 'a2' => 2 } }
27
- described_class.unpatch!(b, diff).should == a
28
- end
29
-
30
- it 'is able to patch value array <=> []' do
31
- a = { 'a' => 1, 'b' => [1, 2] }
32
- b = { 'a' => 1, 'b' => [] }
33
- diff = described_class.diff(a, b)
34
-
35
- expect(described_class.patch!(a, diff)).to eq(b)
36
-
37
- a = { 'a' => 1, 'b' => [1, 2] }
38
- b = { 'a' => 1, 'b' => [] }
39
- described_class.unpatch!(b, diff).should == a
40
- end
41
-
42
- it 'is able to patch value array <=> nil' do
43
- a = { 'a' => 1, 'b' => [1, 2] }
44
- b = { 'a' => 1, 'b' => nil }
45
- diff = described_class.diff(a, b)
46
-
47
- expect(described_class.patch!(a, diff)).to eq(b)
48
-
49
- a = { 'a' => 1, 'b' => [1, 2] }
50
- b = { 'a' => 1, 'b' => nil }
51
- described_class.unpatch!(b, diff).should == a
52
- end
53
-
54
- it 'is able to patch array value removal' do
55
- a = { 'a' => 1, 'b' => [1, 2] }
56
- b = { 'a' => 1 }
57
- diff = described_class.diff(a, b)
58
-
59
- expect(described_class.patch!(a, diff)).to eq(b)
60
-
61
- a = { 'a' => 1, 'b' => [1, 2] }
62
- b = { 'a' => 1 }
63
- described_class.unpatch!(b, diff).should == a
64
- end
65
-
66
- it 'is able to patch array under hash key with non-word characters' do
67
- a = { 'a' => 1, 'b-b' => [1, 2] }
68
- b = { 'a' => 1, 'b-b' => [2, 1] }
69
- diff = described_class.diff(a, b)
70
-
71
- expect(described_class.patch!(a, diff)).to eq(b)
72
-
73
- a = { 'a' => 1, 'b-b' => [1, 2] }
74
- b = { 'a' => 1, 'b-b' => [2, 1] }
75
- described_class.unpatch!(b, diff).should == a
76
- end
77
-
78
- it 'is able to patch hash value removal' do
79
- a = { 'a' => 1, 'b' => { 'b1' => 1, 'b2' => 2 } }
80
- b = { 'a' => 1 }
81
- diff = described_class.diff(a, b)
82
-
83
- expect(described_class.patch!(a, diff)).to eq(b)
84
-
85
- a = { 'a' => 1, 'b' => { 'b1' => 1, 'b2' => 2 } }
86
- b = { 'a' => 1 }
87
- described_class.unpatch!(b, diff).should == a
88
- end
89
-
90
- it 'is able to patch value hash <=> {}' do
91
- a = { 'a' => 1, 'b' => { 'b1' => 1, 'b2' => 2 } }
92
- b = { 'a' => 1, 'b' => {} }
93
- diff = described_class.diff(a, b)
94
-
95
- expect(described_class.patch!(a, diff)).to eq(b)
96
-
97
- a = { 'a' => 1, 'b' => { 'b1' => 1, 'b2' => 2 } }
98
- b = { 'a' => 1, 'b' => {} }
99
- described_class.unpatch!(b, diff).should == a
100
- end
101
-
102
- it 'is able to patch value hash <=> nil' do
103
- a = { 'a' => 1, 'b' => { 'b1' => 1, 'b2' => 2 } }
104
- b = { 'a' => 1, 'b' => nil }
105
- diff = described_class.diff(a, b)
106
-
107
- expect(described_class.patch!(a, diff)).to eq(b)
108
-
109
- a = { 'a' => 1, 'b' => { 'b1' => 1, 'b2' => 2 } }
110
- b = { 'a' => 1, 'b' => nil }
111
- described_class.unpatch!(b, diff).should == a
112
- end
113
-
114
- it 'is able to patch value nil removal' do
115
- a = { 'a' => 1, 'b' => nil }
116
- b = { 'a' => 1 }
117
- diff = described_class.diff(a, b)
118
-
119
- expect(described_class.patch!(a, diff)).to eq(b)
120
-
121
- a = { 'a' => 1, 'b' => nil }
122
- b = { 'a' => 1 }
123
- described_class.unpatch!(b, diff).should == a
124
- end
125
-
126
- it 'is able to patch similar objects between arrays' do
127
- a = [{ 'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5 }, 3]
128
- b = [1, { 'a' => 1, 'b' => 2, 'c' => 3, 'e' => 5 }]
129
-
130
- diff = described_class.diff(a, b)
131
- expect(described_class.patch!(a, diff)).to eq(b)
132
-
133
- a = [{ 'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5 }, 3]
134
- b = [1, { 'a' => 1, 'b' => 2, 'c' => 3, 'e' => 5 }]
135
- described_class.unpatch!(b, diff).should == a
136
- end
137
-
138
- it 'is able to patch similar & equal objects between arrays' do
139
- a = [{ 'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5 }, { 'x' => 5, 'y' => 6, 'z' => 3 }, 1]
140
- b = [1, { 'a' => 1, 'b' => 2, 'c' => 3, 'e' => 5 }]
141
-
142
- diff = described_class.diff(a, b)
143
- expect(described_class.patch!(a, diff)).to eq(b)
144
-
145
- a = [{ 'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5 }, { 'x' => 5, 'y' => 6, 'z' => 3 }, 1]
146
- b = [1, { 'a' => 1, 'b' => 2, 'c' => 3, 'e' => 5 }]
147
- described_class.unpatch!(b, diff).should == a
148
- end
149
-
150
- it 'is able to patch hash value removal with custom delimiter' do
151
- a = { 'a' => 1, 'b' => { 'b1' => 1, 'b2' => 2 } }
152
- b = { 'a' => 1, 'b' => { 'b1' => 3 } }
153
- diff = described_class.diff(a, b, delimiter: "\n")
154
-
155
- expect(described_class.patch!(a, diff, delimiter: "\n")).to eq(b)
156
-
157
- a = { 'a' => 1, 'b' => { 'b1' => 1, 'b2' => 2 } }
158
- b = { 'a' => 1, 'b' => { 'b1' => 3 } }
159
- described_class.unpatch!(b, diff, delimiter: "\n").should == a
160
- end
161
-
162
- it 'is able to patch when the diff is generated with an array_path' do
163
- a = { 'a' => 1, 'b' => 1 }
164
- b = { 'a' => 1, 'b' => 2 }
165
- diff = described_class.diff(a, b, array_path: true)
166
-
167
- expect(described_class.patch!(a, diff)).to eq(b)
168
-
169
- a = { 'a' => 1, 'b' => 1 }
170
- b = { 'a' => 1, 'b' => 2 }
171
- described_class.unpatch!(b, diff).should == a
172
- end
173
-
174
- it 'is able to use non string keys when diff is generated with an array_path' do
175
- a = { 'a' => 1, :a => 2, 0 => 3 }
176
- b = { 'a' => 5, :a => 6, 0 => 7 }
177
- diff = described_class.diff(a, b, array_path: true)
178
-
179
- expect(described_class.patch!(a, diff)).to eq(b)
180
-
181
- a = { 'a' => 1, :a => 2, 0 => 3 }
182
- b = { 'a' => 5, :a => 6, 0 => 7 }
183
- described_class.unpatch!(b, diff).should == a
184
- end
185
- end
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- describe 'README.md' do
6
- it 'has correct examples' do
7
- File.read('README.md').scan(/```ruby(.*?)```/m).flatten(1).each do |block|
8
- begin
9
- eval block # rubocop:disable Security/Eval
10
- rescue Exception => e # rubocop:disable Lint/RescueException
11
- raise "README.md code block:\n#{block}\n\nhas error:\n#{e}"
12
- end
13
- end
14
- end
15
- end
@@ -1,116 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- describe Hashdiff do
6
- it 'is able to decode property path' do
7
- decoded = described_class.send(:decode_property_path, 'a.b[0].c.city[5]')
8
- decoded.should == ['a', 'b', 0, 'c', 'city', 5]
9
- end
10
-
11
- it 'is able to decode property path with custom delimiter' do
12
- decoded = described_class.send(:decode_property_path, "a\tb[0]\tc\tcity[5]", "\t")
13
- decoded.should == ['a', 'b', 0, 'c', 'city', 5]
14
- end
15
-
16
- it 'is able to tell similiar hash' do
17
- a = { 'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5 }
18
- b = { 'a' => 1, 'b' => 2, 'c' => 3, 'e' => 5 }
19
- described_class.similar?(a, b).should be true
20
- described_class.similar?(a, b, similarity: 1).should be false
21
- end
22
-
23
- it 'is able to tell similiar empty hash' do
24
- described_class.similar?({}, {}, similarity: 1).should be true
25
- end
26
-
27
- it 'is able to tell similiar empty array' do
28
- described_class.similar?([], [], similarity: 1).should be true
29
- end
30
-
31
- it 'is able to tell similiar hash with values within tolerance' do
32
- a = { 'a' => 1.5, 'b' => 2.25, 'c' => 3, 'd' => 4, 'e' => 5 }
33
- b = { 'a' => 1.503, 'b' => 2.22, 'c' => 3, 'e' => 5 }
34
- described_class.similar?(a, b, numeric_tolerance: 0.05).should be true
35
- described_class.similar?(a, b).should be false
36
- end
37
-
38
- it 'is able to tell numbers and strings' do
39
- described_class.similar?(1, 2).should be false
40
- described_class.similar?('a', 'b').should be false
41
- described_class.similar?('a', [1, 2, 3]).should be false
42
- described_class.similar?(1, 'a' => 1, 'b' => 2, 'c' => 3, 'e' => 5).should be false
43
- end
44
-
45
- it 'is able to tell true when similarity == 0.5' do
46
- a = { 'value' => 'New1', 'onclick' => 'CreateNewDoc()' }
47
- b = { 'value' => 'New', 'onclick' => 'CreateNewDoc()' }
48
-
49
- described_class.similar?(a, b, similarity: 0.5).should be true
50
- end
51
-
52
- it 'is able to tell false when similarity == 0.5' do
53
- a = { 'value' => 'New1', 'onclick' => 'open()' }
54
- b = { 'value' => 'New', 'onclick' => 'CreateNewDoc()' }
55
-
56
- described_class.similar?(a, b, similarity: 0.5).should be false
57
- end
58
-
59
- describe '.compare_values' do
60
- it 'compares numeric values exactly when no tolerance' do
61
- expect(described_class.compare_values(10.004, 10.003)).to be false
62
- end
63
-
64
- it 'allows tolerance with numeric values' do
65
- expect(described_class.compare_values(10.004, 10.003, numeric_tolerance: 0.01)).to be true
66
- end
67
-
68
- it 'compares different objects without tolerance' do
69
- expect(described_class.compare_values('hats', 'ninjas')).to be false
70
- end
71
-
72
- it 'compares other objects with tolerance' do
73
- expect(described_class.compare_values('hats', 'ninjas', numeric_tolerance: 0.01)).to be false
74
- end
75
-
76
- it 'compares same objects without tolerance' do
77
- expect(described_class.compare_values('horse', 'horse')).to be true
78
- end
79
-
80
- it 'compares strings for spaces exactly by default' do
81
- expect(described_class.compare_values(' horse', 'horse')).to be false
82
- end
83
-
84
- it 'compares strings for capitalization exactly by default' do
85
- expect(described_class.compare_values('horse', 'Horse')).to be false
86
- end
87
-
88
- it 'strips strings before comparing when requested' do
89
- expect(described_class.compare_values(' horse', 'horse', strip: true)).to be true
90
- end
91
-
92
- it 'ignores string case when requested' do
93
- expect(described_class.compare_values('horse', 'Horse', case_insensitive: true)).to be true
94
- end
95
- end
96
-
97
- describe '.comparable?' do
98
- it 'identifies hashes as comparable' do
99
- expect(described_class.comparable?({}, {})).to be true
100
- end
101
-
102
- it 'identifies a subclass of Hash to be comparable with a Hash' do
103
- other = Class.new(Hash)
104
- expect(described_class.comparable?(other.new, {})).to be true
105
- end
106
-
107
- it 'identifies a Hash to be comparable with a subclass of Hash' do
108
- other = Class.new(Hash)
109
- expect(described_class.comparable?({}, other.new)).to be true
110
- end
111
-
112
- it 'does not identify a Numeric as comparable with a Hash' do
113
- expect(described_class.comparable?(1, {})).to be false
114
- end
115
- end
116
- end
data/spec/spec_helper.rb DELETED
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- $LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib')
4
-
5
- require 'rubygems'
6
- require 'rspec'
7
- require 'rspec/autorun'
8
-
9
- require 'hashdiff'
10
-
11
- RSpec.configure do |config|
12
- config.mock_framework = :rspec
13
-
14
- config.include RSpec::Matchers
15
- end