hashdiff 0.3.7 → 0.3.8

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.
@@ -0,0 +1,74 @@
1
+ require 'spec_helper'
2
+
3
+ describe HashDiff do
4
+ it 'is able to find LCS between two equal array' do
5
+ a = [1, 2, 3]
6
+ b = [1, 2, 3]
7
+
8
+ lcs = described_class.lcs(a, b)
9
+ lcs.should == [[0, 0], [1, 1], [2, 2]]
10
+ end
11
+
12
+ it 'is able to find LCS between two close arrays' do
13
+ a = [1.05, 2, 3.25]
14
+ b = [1.06, 2, 3.24]
15
+
16
+ lcs = described_class.lcs(a, b, numeric_tolerance: 0.1)
17
+ lcs.should == [[0, 0], [1, 1], [2, 2]]
18
+ end
19
+
20
+ it 'strips strings when finding LCS if requested' do
21
+ a = %w[foo bar baz]
22
+ b = [' foo', 'bar', 'zab']
23
+
24
+ lcs = described_class.lcs(a, b, strip: true)
25
+ lcs.should == [[0, 0], [1, 1]]
26
+ end
27
+
28
+ it 'is able to find LCS with one common elements' do
29
+ a = [1, 2, 3]
30
+ b = [1, 8, 7]
31
+
32
+ lcs = described_class.lcs(a, b)
33
+ lcs.should == [[0, 0]]
34
+ end
35
+
36
+ it 'is able to find LCS with two common elements' do
37
+ a = [1, 3, 5, 7]
38
+ b = [2, 3, 7, 5]
39
+
40
+ lcs = described_class.lcs(a, b)
41
+ lcs.should == [[1, 1], [2, 3]]
42
+ end
43
+
44
+ it 'is able to find LCS with two close elements' do
45
+ a = [1, 3.05, 5, 7]
46
+ b = [2, 3.06, 7, 5]
47
+
48
+ lcs = described_class.lcs(a, b, numeric_tolerance: 0.1)
49
+ lcs.should == [[1, 1], [2, 3]]
50
+ end
51
+
52
+ it 'is able to find LCS with two common elements in different ordering' do
53
+ a = [1, 3, 4, 7]
54
+ b = [2, 3, 7, 5]
55
+
56
+ lcs = described_class.lcs(a, b)
57
+ lcs.should == [[1, 1], [3, 2]]
58
+ end
59
+
60
+ it 'is able to find LCS with a similarity value' do
61
+ a = [
62
+ { 'value' => 'New', 'onclick' => 'CreateNewDoc()' },
63
+ { 'value' => 'Close', 'onclick' => 'CloseDoc()' }
64
+ ]
65
+ b = [
66
+ { 'value' => 'New1', 'onclick' => 'CreateNewDoc()' },
67
+ { 'value' => 'Open', 'onclick' => 'OpenDoc()' },
68
+ { 'value' => 'Close', 'onclick' => 'CloseDoc()' }
69
+ ]
70
+
71
+ lcs = described_class.lcs(a, b, similarity: 0.5)
72
+ lcs.should == [[0, 0], [1, 2]]
73
+ end
74
+ end
@@ -0,0 +1,48 @@
1
+ require 'spec_helper'
2
+
3
+ describe HashDiff::LinearCompareArray do
4
+ it 'finds no differences between two empty arrays' do
5
+ difference = described_class.call([], [])
6
+ difference.should == []
7
+ end
8
+
9
+ it 'finds added items when the old array is empty' do
10
+ difference = described_class.call([], %i[a b])
11
+ difference.should == [['+', '[0]', :a], ['+', '[1]', :b]]
12
+ end
13
+
14
+ it 'finds removed items when the new array is empty' do
15
+ difference = described_class.call(%i[a b], [])
16
+ difference.should == [['-', '[1]', :b], ['-', '[0]', :a]]
17
+ end
18
+
19
+ it 'finds no differences between identical arrays' do
20
+ difference = described_class.call(%i[a b], %i[a b])
21
+ difference.should == []
22
+ end
23
+
24
+ it 'finds added items in an array' do
25
+ difference = described_class.call(%i[a d], %i[a b c d])
26
+ difference.should == [['+', '[1]', :b], ['+', '[2]', :c]]
27
+ end
28
+
29
+ it 'finds removed items in an array' do
30
+ difference = described_class.call(%i[a b c d e f], %i[a d f])
31
+ difference.should == [['-', '[4]', :e], ['-', '[2]', :c], ['-', '[1]', :b]]
32
+ end
33
+
34
+ it 'shows additions and deletions as changed items' do
35
+ difference = described_class.call(%i[a b c], %i[c b a])
36
+ difference.should == [['~', '[0]', :a, :c], ['~', '[2]', :c, :a]]
37
+ end
38
+
39
+ it 'shows changed items in a hash' do
40
+ difference = described_class.call([{ a: :b }], [{ a: :c }])
41
+ difference.should == [['~', '[0].a', :b, :c]]
42
+ end
43
+
44
+ it 'shows changed items and added items' do
45
+ difference = described_class.call([{ a: 1, b: 2 }], [{ a: 2, b: 2 }, :item])
46
+ difference.should == [['~', '[0].a', 1, 2], ['+', '[1]', :item]]
47
+ end
48
+ end
@@ -0,0 +1,183 @@
1
+ require 'spec_helper'
2
+
3
+ describe HashDiff do
4
+ it 'is able to patch key addition' do
5
+ a = { 'a' => 3, 'c' => 11, 'd' => 45, 'e' => 100, 'f' => 200 }
6
+ b = { 'a' => 3, 'c' => 11, 'd' => 45, 'e' => 100, 'f' => 200, 'g' => 300 }
7
+ diff = described_class.diff(a, b)
8
+
9
+ expect(described_class.patch!(a, diff)).to eq(b)
10
+
11
+ a = { 'a' => 3, 'c' => 11, 'd' => 45, 'e' => 100, 'f' => 200 }
12
+ b = { 'a' => 3, 'c' => 11, 'd' => 45, 'e' => 100, 'f' => 200, 'g' => 300 }
13
+ described_class.unpatch!(b, diff).should == a
14
+ end
15
+
16
+ it 'is able to patch value type changes' do
17
+ a = { 'a' => 3 }
18
+ b = { 'a' => { 'a1' => 1, 'a2' => 2 } }
19
+ diff = described_class.diff(a, b)
20
+
21
+ expect(described_class.patch!(a, diff)).to eq(b)
22
+
23
+ a = { 'a' => 3 }
24
+ b = { 'a' => { 'a1' => 1, 'a2' => 2 } }
25
+ described_class.unpatch!(b, diff).should == a
26
+ end
27
+
28
+ it 'is able to patch value array <=> []' do
29
+ a = { 'a' => 1, 'b' => [1, 2] }
30
+ b = { 'a' => 1, 'b' => [] }
31
+ diff = described_class.diff(a, b)
32
+
33
+ expect(described_class.patch!(a, diff)).to eq(b)
34
+
35
+ a = { 'a' => 1, 'b' => [1, 2] }
36
+ b = { 'a' => 1, 'b' => [] }
37
+ described_class.unpatch!(b, diff).should == a
38
+ end
39
+
40
+ it 'is able to patch value array <=> nil' do
41
+ a = { 'a' => 1, 'b' => [1, 2] }
42
+ b = { 'a' => 1, 'b' => nil }
43
+ diff = described_class.diff(a, b)
44
+
45
+ expect(described_class.patch!(a, diff)).to eq(b)
46
+
47
+ a = { 'a' => 1, 'b' => [1, 2] }
48
+ b = { 'a' => 1, 'b' => nil }
49
+ described_class.unpatch!(b, diff).should == a
50
+ end
51
+
52
+ it 'is able to patch array value removal' do
53
+ a = { 'a' => 1, 'b' => [1, 2] }
54
+ b = { 'a' => 1 }
55
+ diff = described_class.diff(a, b)
56
+
57
+ expect(described_class.patch!(a, diff)).to eq(b)
58
+
59
+ a = { 'a' => 1, 'b' => [1, 2] }
60
+ b = { 'a' => 1 }
61
+ described_class.unpatch!(b, diff).should == a
62
+ end
63
+
64
+ it 'is able to patch array under hash key with non-word characters' do
65
+ a = { 'a' => 1, 'b-b' => [1, 2] }
66
+ b = { 'a' => 1, 'b-b' => [2, 1] }
67
+ diff = described_class.diff(a, b)
68
+
69
+ expect(described_class.patch!(a, diff)).to eq(b)
70
+
71
+ a = { 'a' => 1, 'b-b' => [1, 2] }
72
+ b = { 'a' => 1, 'b-b' => [2, 1] }
73
+ described_class.unpatch!(b, diff).should == a
74
+ end
75
+
76
+ it 'is able to patch hash value removal' do
77
+ a = { 'a' => 1, 'b' => { 'b1' => 1, 'b2' => 2 } }
78
+ b = { 'a' => 1 }
79
+ diff = described_class.diff(a, b)
80
+
81
+ expect(described_class.patch!(a, diff)).to eq(b)
82
+
83
+ a = { 'a' => 1, 'b' => { 'b1' => 1, 'b2' => 2 } }
84
+ b = { 'a' => 1 }
85
+ described_class.unpatch!(b, diff).should == a
86
+ end
87
+
88
+ it 'is able to patch value hash <=> {}' do
89
+ a = { 'a' => 1, 'b' => { 'b1' => 1, 'b2' => 2 } }
90
+ b = { 'a' => 1, 'b' => {} }
91
+ diff = described_class.diff(a, b)
92
+
93
+ expect(described_class.patch!(a, diff)).to eq(b)
94
+
95
+ a = { 'a' => 1, 'b' => { 'b1' => 1, 'b2' => 2 } }
96
+ b = { 'a' => 1, 'b' => {} }
97
+ described_class.unpatch!(b, diff).should == a
98
+ end
99
+
100
+ it 'is able to patch value hash <=> nil' do
101
+ a = { 'a' => 1, 'b' => { 'b1' => 1, 'b2' => 2 } }
102
+ b = { 'a' => 1, 'b' => nil }
103
+ diff = described_class.diff(a, b)
104
+
105
+ expect(described_class.patch!(a, diff)).to eq(b)
106
+
107
+ a = { 'a' => 1, 'b' => { 'b1' => 1, 'b2' => 2 } }
108
+ b = { 'a' => 1, 'b' => nil }
109
+ described_class.unpatch!(b, diff).should == a
110
+ end
111
+
112
+ it 'is able to patch value nil removal' do
113
+ a = { 'a' => 1, 'b' => nil }
114
+ b = { 'a' => 1 }
115
+ diff = described_class.diff(a, b)
116
+
117
+ expect(described_class.patch!(a, diff)).to eq(b)
118
+
119
+ a = { 'a' => 1, 'b' => nil }
120
+ b = { 'a' => 1 }
121
+ described_class.unpatch!(b, diff).should == a
122
+ end
123
+
124
+ it 'is able to patch similar objects between arrays' do
125
+ a = [{ 'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5 }, 3]
126
+ b = [1, { 'a' => 1, 'b' => 2, 'c' => 3, 'e' => 5 }]
127
+
128
+ diff = described_class.diff(a, b)
129
+ expect(described_class.patch!(a, diff)).to eq(b)
130
+
131
+ a = [{ 'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5 }, 3]
132
+ b = [1, { 'a' => 1, 'b' => 2, 'c' => 3, 'e' => 5 }]
133
+ described_class.unpatch!(b, diff).should == a
134
+ end
135
+
136
+ it 'is able to patch similar & equal objects between arrays' do
137
+ a = [{ 'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5 }, { 'x' => 5, 'y' => 6, 'z' => 3 }, 1]
138
+ b = [1, { 'a' => 1, 'b' => 2, 'c' => 3, 'e' => 5 }]
139
+
140
+ diff = described_class.diff(a, b)
141
+ expect(described_class.patch!(a, diff)).to eq(b)
142
+
143
+ a = [{ 'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5 }, { 'x' => 5, 'y' => 6, 'z' => 3 }, 1]
144
+ b = [1, { 'a' => 1, 'b' => 2, 'c' => 3, 'e' => 5 }]
145
+ described_class.unpatch!(b, diff).should == a
146
+ end
147
+
148
+ it 'is able to patch hash value removal with custom delimiter' do
149
+ a = { 'a' => 1, 'b' => { 'b1' => 1, 'b2' => 2 } }
150
+ b = { 'a' => 1, 'b' => { 'b1' => 3 } }
151
+ diff = described_class.diff(a, b, delimiter: "\n")
152
+
153
+ expect(described_class.patch!(a, diff, delimiter: "\n")).to eq(b)
154
+
155
+ a = { 'a' => 1, 'b' => { 'b1' => 1, 'b2' => 2 } }
156
+ b = { 'a' => 1, 'b' => { 'b1' => 3 } }
157
+ described_class.unpatch!(b, diff, delimiter: "\n").should == a
158
+ end
159
+
160
+ it 'is able to patch when the diff is generated with an array_path' do
161
+ a = { 'a' => 1, 'b' => 1 }
162
+ b = { 'a' => 1, 'b' => 2 }
163
+ diff = described_class.diff(a, b, array_path: true)
164
+
165
+ expect(described_class.patch!(a, diff)).to eq(b)
166
+
167
+ a = { 'a' => 1, 'b' => 1 }
168
+ b = { 'a' => 1, 'b' => 2 }
169
+ described_class.unpatch!(b, diff).should == a
170
+ end
171
+
172
+ it 'is able to use non string keys when diff is generated with an array_path' do
173
+ a = { 'a' => 1, :a => 2, 0 => 3 }
174
+ b = { 'a' => 5, :a => 6, 0 => 7 }
175
+ diff = described_class.diff(a, b, array_path: true)
176
+
177
+ expect(described_class.patch!(a, diff)).to eq(b)
178
+
179
+ a = { 'a' => 1, :a => 2, 0 => 3 }
180
+ b = { 'a' => 5, :a => 6, 0 => 7 }
181
+ described_class.unpatch!(b, diff).should == a
182
+ end
183
+ end
@@ -0,0 +1,85 @@
1
+ require 'spec_helper'
2
+
3
+ describe HashDiff do
4
+ it 'is able to decode property path' do
5
+ decoded = described_class.send(:decode_property_path, 'a.b[0].c.city[5]')
6
+ decoded.should == ['a', 'b', 0, 'c', 'city', 5]
7
+ end
8
+
9
+ it 'is able to decode property path with custom delimiter' do
10
+ decoded = described_class.send(:decode_property_path, "a\tb[0]\tc\tcity[5]", "\t")
11
+ decoded.should == ['a', 'b', 0, 'c', 'city', 5]
12
+ end
13
+
14
+ it 'is able to tell similiar hash' do
15
+ a = { 'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5 }
16
+ b = { 'a' => 1, 'b' => 2, 'c' => 3, 'e' => 5 }
17
+ described_class.similar?(a, b).should be true
18
+ described_class.similar?(a, b, similarity: 1).should be false
19
+ end
20
+
21
+ it 'is able to tell similiar hash with values within tolerance' do
22
+ a = { 'a' => 1.5, 'b' => 2.25, 'c' => 3, 'd' => 4, 'e' => 5 }
23
+ b = { 'a' => 1.503, 'b' => 2.22, 'c' => 3, 'e' => 5 }
24
+ described_class.similar?(a, b, numeric_tolerance: 0.05).should be true
25
+ described_class.similar?(a, b).should be false
26
+ end
27
+
28
+ it 'is able to tell numbers and strings' do
29
+ described_class.similar?(1, 2).should be false
30
+ described_class.similar?('a', 'b').should be false
31
+ described_class.similar?('a', [1, 2, 3]).should be false
32
+ described_class.similar?(1, 'a' => 1, 'b' => 2, 'c' => 3, 'e' => 5).should be false
33
+ end
34
+
35
+ it 'is able to tell true when similarity == 0.5' do
36
+ a = { 'value' => 'New1', 'onclick' => 'CreateNewDoc()' }
37
+ b = { 'value' => 'New', 'onclick' => 'CreateNewDoc()' }
38
+
39
+ described_class.similar?(a, b, similarity: 0.5).should be true
40
+ end
41
+
42
+ it 'is able to tell false when similarity == 0.5' do
43
+ a = { 'value' => 'New1', 'onclick' => 'open()' }
44
+ b = { 'value' => 'New', 'onclick' => 'CreateNewDoc()' }
45
+
46
+ described_class.similar?(a, b, similarity: 0.5).should be false
47
+ end
48
+
49
+ describe '.compare_values' do
50
+ it 'compares numeric values exactly when no tolerance' do
51
+ expect(described_class.compare_values(10.004, 10.003)).to be false
52
+ end
53
+
54
+ it 'allows tolerance with numeric values' do
55
+ expect(described_class.compare_values(10.004, 10.003, numeric_tolerance: 0.01)).to be true
56
+ end
57
+
58
+ it 'compares different objects without tolerance' do
59
+ expect(described_class.compare_values('hats', 'ninjas')).to be false
60
+ end
61
+ it 'compares other objects with tolerance' do
62
+ expect(described_class.compare_values('hats', 'ninjas', numeric_tolerance: 0.01)).to be false
63
+ end
64
+
65
+ it 'compares same objects without tolerance' do
66
+ expect(described_class.compare_values('horse', 'horse')).to be true
67
+ end
68
+
69
+ it 'compares strings for spaces exactly by default' do
70
+ expect(described_class.compare_values(' horse', 'horse')).to be false
71
+ end
72
+
73
+ it 'compares strings for capitalization exactly by default' do
74
+ expect(described_class.compare_values('horse', 'Horse')).to be false
75
+ end
76
+
77
+ it 'strips strings before comparing when requested' do
78
+ expect(described_class.compare_values(' horse', 'horse', strip: true)).to be true
79
+ end
80
+
81
+ it 'ignores string case when requested' do
82
+ expect(described_class.compare_values('horse', 'Horse', case_insensitive: true)).to be true
83
+ end
84
+ end
85
+ end
metadata CHANGED
@@ -1,69 +1,98 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hashdiff
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.7
4
+ version: 0.3.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Liu Fengyun
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-10-08 00:00:00.000000000 Z
11
+ date: 2018-12-30 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bluecloth
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: rspec
15
29
  requirement: !ruby/object:Gem::Requirement
16
30
  requirements:
17
- - - ~>
31
+ - - "~>"
18
32
  - !ruby/object:Gem::Version
19
33
  version: '2.0'
20
34
  type: :development
21
35
  prerelease: false
22
36
  version_requirements: !ruby/object:Gem::Requirement
23
37
  requirements:
24
- - - ~>
38
+ - - "~>"
25
39
  - !ruby/object:Gem::Version
26
40
  version: '2.0'
27
41
  - !ruby/object:Gem::Dependency
28
- name: yard
42
+ name: rubocop
29
43
  requirement: !ruby/object:Gem::Requirement
30
44
  requirements:
31
- - - '>='
45
+ - - ">="
32
46
  - !ruby/object:Gem::Version
33
47
  version: '0'
34
48
  type: :development
35
49
  prerelease: false
36
50
  version_requirements: !ruby/object:Gem::Requirement
37
51
  requirements:
38
- - - '>='
52
+ - - ">="
39
53
  - !ruby/object:Gem::Version
40
54
  version: '0'
41
55
  - !ruby/object:Gem::Dependency
42
- name: bluecloth
56
+ name: rubocop-rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: yard
43
71
  requirement: !ruby/object:Gem::Requirement
44
72
  requirements:
45
- - - '>='
73
+ - - ">="
46
74
  - !ruby/object:Gem::Version
47
75
  version: '0'
48
76
  type: :development
49
77
  prerelease: false
50
78
  version_requirements: !ruby/object:Gem::Requirement
51
79
  requirements:
52
- - - '>='
80
+ - - ">="
53
81
  - !ruby/object:Gem::Version
54
82
  version: '0'
55
- description: ' HashDiff is a diff lib to compute the smallest difference between two
56
- hashes. '
83
+ description: " HashDiff is a diff lib to compute the smallest difference between two
84
+ hashes. "
57
85
  email:
58
86
  - liufengyunchina@gmail.com
59
87
  executables: []
60
88
  extensions: []
61
89
  extra_rdoc_files: []
62
90
  files:
63
- - .gitignore
64
- - .rspec
65
- - .travis.yml
66
- - .yardopts
91
+ - ".gitignore"
92
+ - ".rspec"
93
+ - ".rubocop.yml"
94
+ - ".travis.yml"
95
+ - ".yardopts"
67
96
  - Gemfile
68
97
  - LICENSE
69
98
  - README.md
@@ -77,13 +106,13 @@ files:
77
106
  - lib/hashdiff/patch.rb
78
107
  - lib/hashdiff/util.rb
79
108
  - lib/hashdiff/version.rb
80
- - spec/hashdiff/best_diff_spec.rb
81
- - spec/hashdiff/diff_array_spec.rb
82
- - spec/hashdiff/diff_spec.rb
83
- - spec/hashdiff/lcs_spec.rb
84
- - spec/hashdiff/linear_compare_array_spec.rb
85
- - spec/hashdiff/patch_spec.rb
86
- - spec/hashdiff/util_spec.rb
109
+ - spec/hash_diff/best_diff_spec.rb
110
+ - spec/hash_diff/diff_array_spec.rb
111
+ - spec/hash_diff/diff_spec.rb
112
+ - spec/hash_diff/lcs_spec.rb
113
+ - spec/hash_diff/linear_compare_array_spec.rb
114
+ - spec/hash_diff/patch_spec.rb
115
+ - spec/hash_diff/util_spec.rb
87
116
  - spec/spec_helper.rb
88
117
  homepage: https://github.com/liufengyun/hashdiff
89
118
  licenses:
@@ -95,17 +124,17 @@ require_paths:
95
124
  - lib
96
125
  required_ruby_version: !ruby/object:Gem::Requirement
97
126
  requirements:
98
- - - '>='
127
+ - - ">="
99
128
  - !ruby/object:Gem::Version
100
129
  version: 1.9.3
101
130
  required_rubygems_version: !ruby/object:Gem::Requirement
102
131
  requirements:
103
- - - '>='
132
+ - - ">="
104
133
  - !ruby/object:Gem::Version
105
134
  version: '0'
106
135
  requirements: []
107
136
  rubyforge_project:
108
- rubygems_version: 2.0.14.1
137
+ rubygems_version: 2.5.2.3
109
138
  signing_key:
110
139
  specification_version: 4
111
140
  summary: HashDiff is a diff lib to compute the smallest difference between two hashes.