hashdiff 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,6 @@
1
1
  language: ruby
2
2
  rvm:
3
+ - 1.8.7
3
4
  - 1.9.3
4
5
  - 2.0.0
5
6
  - 2.1.1
data/README.md CHANGED
@@ -8,7 +8,7 @@ HashDiff is a ruby library to compute the smallest difference between two hashes
8
8
 
9
9
  ## Why HashDiff?
10
10
 
11
- Given two Hashes A and B, sometimes you face the question: what's the smallest changes that can be made to change A to B?
11
+ Given two Hashes A and B, sometimes you face the question: what's the smallest modification that can be made to change A into B?
12
12
 
13
13
  An algorithm that responds to this question has to do following:
14
14
 
@@ -16,11 +16,11 @@ An algorithm that responds to this question has to do following:
16
16
  * Compute recursively -- Arrays and Hashes may be nested arbitrarily in A or B.
17
17
  * Compute the smallest change -- it should recognize similar child Hashes or child Arrays between A and B.
18
18
 
19
- HashDiff answers the question above in an opinionated approach:
19
+ HashDiff answers the question above using an opinionated approach:
20
20
 
21
21
  * Hash can be represented as a list of (dot-syntax-path, value) pairs. For example, `{a:[{c:2}]}` can be represented as `["a[0].c", 2]`.
22
22
  * The change set can be represented using the dot-syntax representation. For example, `[['-', 'b.x', 3], ['~', 'b.z', 45, 30], ['+', 'b.y', 3]]`.
23
- * It compares Arrays using LCS(longest common subsequence) algorithm.
23
+ * It compares Arrays using the [LCS(longest common subsequence)](http://en.wikipedia.org/wiki/Longest_common_subsequence_problem) algorithm.
24
24
  * It recognizes similar Hashes in an Array using a similarity value (0 < similarity <= 1).
25
25
 
26
26
  ## Usage
@@ -171,6 +171,38 @@ diff.should == [["~", "a", "car", "bus"], ["~", "b[1]", "plane", " plan"], ["-",
171
171
 
172
172
  When a comparison block is given, it'll be given priority over other specified options. If the block returns value other than `true` or `false`, then the two values will be compared with other specified options.
173
173
 
174
+ #### Sorting arrays before comparison
175
+
176
+ An order difference alone between two arrays can create too many diffs to be useful. Consider sorting them prior to diffing.
177
+
178
+ ```ruby
179
+ a = {a:'car', b:['boat', 'plane'] }
180
+ b = {a:'car', b:['plane', 'boat'] }
181
+
182
+ HashDiff.diff(a, b) => [["+", "b[0]", "plane"], ["-", "b[2]", "plane"]]
183
+
184
+ b[:b].sort!
185
+
186
+ HashDiff.diff(a, b) => []
187
+ ```
188
+
189
+ ### Special use cases
190
+
191
+ #### Using HashDiff on JSON API results
192
+
193
+ ```ruby
194
+ require 'uri'
195
+ require 'net/http'
196
+ require 'json'
197
+
198
+ uri = URI('http://time.jsontest.com/')
199
+ json_resp = ->(uri) { JSON.parse(Net::HTTP.get_response(uri).body) }
200
+ a = json_resp.call(uri)
201
+ b = json_resp.call(uri)
202
+
203
+ HashDiff.diff(a,b) => [["~", "milliseconds_since_epoch", 1410542545874, 1410542545985]]
204
+ ```
205
+
174
206
  ## License
175
207
 
176
208
  HashDiff is distributed under the MIT-LICENSE.
@@ -1,5 +1,9 @@
1
1
  # Change Log
2
2
 
3
+ ## v0.2.2 2014-10-6
4
+
5
+ * make library 1.8.7 compatible
6
+
3
7
  ## v0.2.1 2014-7-13
4
8
 
5
9
  * yield added/deleted keys for custom comparison
@@ -27,15 +27,15 @@ module HashDiff
27
27
  def self.best_diff(obj1, obj2, options = {}, &block)
28
28
  options[:comparison] = block if block_given?
29
29
 
30
- opts = {similarity: 0.3}.merge!(options)
30
+ opts = { :similarity => 0.3 }.merge!(options)
31
31
  diffs_1 = diff(obj1, obj2, opts)
32
32
  count_1 = count_diff diffs_1
33
33
 
34
- opts = {similarity: 0.5}.merge!(options)
34
+ opts = { :similarity => 0.5 }.merge!(options)
35
35
  diffs_2 = diff(obj1, obj2, opts)
36
36
  count_2 = count_diff diffs_2
37
37
 
38
- opts = {similarity: 0.8}.merge!(options)
38
+ opts = { :similarity => 0.8 }.merge!(options)
39
39
  diffs_3 = diff(obj1, obj2, opts)
40
40
  count_3 = count_diff diffs_3
41
41
 
@@ -104,7 +104,7 @@ module HashDiff
104
104
  changeset = diff_array(obj1, obj2, opts) do |lcs|
105
105
  # use a's index for similarity
106
106
  lcs.each do |pair|
107
- result.concat(diff(obj1[pair[0]], obj2[pair[1]], opts.merge(prefix: "#{opts[:prefix]}[#{pair[0]}]")))
107
+ result.concat(diff(obj1[pair[0]], obj2[pair[1]], opts.merge(:prefix => "#{opts[:prefix]}[#{pair[0]}]")))
108
108
  end
109
109
  end
110
110
 
@@ -122,19 +122,12 @@ module HashDiff
122
122
  prefix = "#{opts[:prefix]}#{opts[:delimiter]}"
123
123
  end
124
124
 
125
- deleted_keys = []
126
- common_keys = []
127
-
128
- obj1.each do |k, v|
129
- if obj2.key?(k)
130
- common_keys << k
131
- else
132
- deleted_keys << k
133
- end
134
- end
125
+ deleted_keys = obj1.keys - obj2.keys
126
+ common_keys = obj1.keys & obj2.keys
127
+ added_keys = obj2.keys - obj1.keys
135
128
 
136
129
  # add deleted properties
137
- deleted_keys.each do |k|
130
+ deleted_keys.sort.each do |k|
138
131
  custom_result = custom_compare(opts[:comparison], "#{prefix}#{k}", obj1[k], nil)
139
132
 
140
133
  if custom_result
@@ -145,12 +138,12 @@ module HashDiff
145
138
  end
146
139
 
147
140
  # recursive comparison for common keys
148
- common_keys.each {|k| result.concat(diff(obj1[k], obj2[k], opts.merge(prefix: "#{prefix}#{k}"))) }
141
+ common_keys.sort.each {|k| result.concat(diff(obj1[k], obj2[k], opts.merge(:prefix => "#{prefix}#{k}"))) }
149
142
 
150
143
  # added properties
151
- obj2.each do |k, v|
144
+ added_keys.sort.each do |k|
152
145
  unless obj1.key?(k)
153
- custom_result = custom_compare(opts[:comparison], "#{prefix}#{k}", nil, v)
146
+ custom_result = custom_compare(opts[:comparison], "#{prefix}#{k}", nil, obj2[k])
154
147
 
155
148
  if custom_result
156
149
  result.concat(custom_result)
@@ -1,3 +1,3 @@
1
1
  module HashDiff
2
- VERSION = '0.2.1'
2
+ VERSION = '0.2.2'
3
3
  end
@@ -7,7 +7,7 @@ describe HashDiff do
7
7
  end
8
8
 
9
9
  it "should be able to diff an hash with an empty hash" do
10
- a = {a:3, b:2}
10
+ a = { 'a' => 3, 'b' => 2 }
11
11
  b = {}
12
12
 
13
13
  diff = HashDiff.diff(a, b)
@@ -18,32 +18,34 @@ describe HashDiff do
18
18
  end
19
19
 
20
20
  it "should be able to diff two equal hashes" do
21
- diff = HashDiff.diff({a:2, b:2}, {a:2, b:2})
21
+ diff = HashDiff.diff({ 'a' => 2, 'b' => 2}, { 'a' => 2, 'b' => 2 })
22
22
  diff.should == []
23
23
  end
24
24
 
25
25
  it "should be able to diff two hashes with equivalent numerics, when strict is false" do
26
- diff = HashDiff.diff({a:2.0, b:2}, {a:2, b:2.0}, :strict => false)
26
+ diff = HashDiff.diff({ 'a' => 2.0, 'b' => 2 }, { 'a' => 2, 'b' => 2.0 }, :strict => false)
27
27
  diff.should == []
28
28
  end
29
29
 
30
30
  it "should be able to diff changes in hash value" do
31
- diff = HashDiff.diff({a:2, b:3, c:" hello"}, {a:2, b:4, c:"hello"})
31
+ diff = HashDiff.diff({ 'a' => 2, 'b' => 3, 'c' => " hello" }, { 'a' => 2, 'b' => 4, 'c' => "hello" })
32
32
  diff.should == [['~', 'b', 3, 4], ['~', 'c', " hello", "hello"]]
33
33
  end
34
34
 
35
35
  it "should be able to diff changes in hash value which is array" do
36
- diff = HashDiff.diff({a:2, b:[1, 2, 3]}, {a:2, b:[1, 3, 4]})
36
+ diff = HashDiff.diff({ 'a' => 2, 'b' => [1, 2, 3] }, { 'a' => 2, 'b' => [1, 3, 4]})
37
37
  diff.should == [['-', 'b[1]', 2], ['+', 'b[2]', 4]]
38
38
  end
39
39
 
40
40
  it "should be able to diff changes in hash value which is hash" do
41
- diff = HashDiff.diff({a:{x:2, y:3, z:4}, b:{x:3, z:45}}, {a:{y:3}, b:{y:3, z:30}})
41
+ diff = HashDiff.diff({ 'a' => { 'x' => 2, 'y' => 3, 'z' => 4 }, 'b' => { 'x' => 3, 'z' => 45 } },
42
+ { 'a' => { 'y' => 3 }, 'b' => { 'y' => 3, 'z' => 30 } })
42
43
  diff.should == [['-', 'a.x', 2], ['-', 'a.z', 4], ['-', 'b.x', 3], ['~', 'b.z', 45, 30], ['+', 'b.y', 3]]
43
44
  end
44
45
 
45
46
  it "should be able to diff similar objects in array" do
46
- diff = HashDiff.best_diff({a:[{x:2, y:3, z:4}, {x:11, y:22, z:33}], b:{x:3, z:45}}, {a:[{y:3}, {x:11, z:33}], b:{y:22}})
47
+ diff = HashDiff.best_diff({ 'a' => [{ 'x' => 2, 'y' => 3, 'z' => 4 }, { 'x' => 11, 'y' => 22, 'z' => 33 }], 'b' => { 'x' => 3, 'z' => 45 } },
48
+ { 'a' => [{ 'y' => 3 }, { 'x' => 11, 'z' => 33 }], 'b' => { 'y' => 22 } })
47
49
  diff.should == [['-', 'a[0].x', 2], ['-', 'a[0].z', 4], ['-', 'a[1].y', 22], ['-', 'b.x', 3], ['-', 'b.z', 45], ['+', 'b.y', 22]]
48
50
  end
49
51
 
@@ -137,7 +139,7 @@ describe HashDiff do
137
139
  a = [{'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5}, {'x' => 5, 'y' => 6, 'z' => 3}, 3]
138
140
  b = [{'a' => 1, 'b' => 2, 'c' => 3, 'e' => 5}, 3]
139
141
 
140
- diff = HashDiff.diff(a, b, similarity: 0.8, delimiter: "\t")
142
+ diff = HashDiff.diff(a, b, :similarity => 0.8, :delimiter => "\t")
141
143
  diff.should == [["-", "[0]\td", 4], ["-", "[1]", {"x"=>5, "y"=>6, "z"=>3}]]
142
144
  end
143
145
 
@@ -167,15 +169,15 @@ describe HashDiff do
167
169
 
168
170
  context 'when :strip requested' do
169
171
  it "should strip strings before comparing" do
170
- a = {a:" foo", b:"fizz buzz"}
171
- b = {a:"foo", b:"fizzbuzz"}
172
+ a = { 'a' => " foo", 'b' => "fizz buzz"}
173
+ b = { 'a' => "foo", 'b' => "fizzbuzz"}
172
174
  diff = HashDiff.diff(a, b, :strip => true)
173
175
  diff.should == [['~', 'b', "fizz buzz", "fizzbuzz"]]
174
176
  end
175
177
 
176
178
  it "should strip nested strings before comparing" do
177
- a = {a:{x:" foo"}, b:["fizz buzz", "nerf"]}
178
- b = {a:{x:"foo"}, b:["fizzbuzz", "nerf"]}
179
+ a = { 'a' => { 'x' => " foo" }, 'b' => ["fizz buzz", "nerf"] }
180
+ b = { 'a' => { 'x' => "foo" }, 'b' => ["fizzbuzz", "nerf"] }
179
181
  diff = HashDiff.diff(a, b, :strip => true)
180
182
  diff.should == [['-', 'b[0]', "fizz buzz"], ['+', 'b[0]', "fizzbuzz"]]
181
183
  end
@@ -183,16 +185,16 @@ describe HashDiff do
183
185
 
184
186
  context 'when both :strip and :numeric_tolerance requested' do
185
187
  it 'should apply filters to proper object types' do
186
- a = {a:" foo", b:35, c:'bar', d:'baz'}
187
- b = {a:"foo", b:35.005, c:'bar', d:18.5}
188
+ a = { 'a' => " foo", 'b' => 35, 'c' => 'bar', 'd' => 'baz' }
189
+ b = { 'a' => "foo", 'b' => 35.005, 'c' => 'bar', 'd' => 18.5}
188
190
  diff = HashDiff.diff(a, b, :strict => false, :numeric_tolerance => 0.01, :strip => true)
189
191
  diff.should == [['~', 'd', "baz", 18.5]]
190
192
  end
191
193
  end
192
194
 
193
195
  context 'with custom comparison' do
194
- let(:a) { {a:'car', b:'boat', c:'plane'} }
195
- let(:b) { {a:'bus', b:'truck', c:' plan'} }
196
+ let(:a) { { 'a' => 'car', 'b' => 'boat', 'c' => 'plane'} }
197
+ let(:b) { { 'a' => 'bus', 'b' => 'truck', 'c' => ' plan'} }
196
198
 
197
199
  it 'should compare using proc specified in block' do
198
200
  diff = HashDiff.diff(a, b) do |prefix, obj1, obj2|
@@ -205,8 +207,8 @@ describe HashDiff do
205
207
  end
206
208
 
207
209
  it 'should yield added keys' do
208
- x = {a:'car', b:'boat'}
209
- y = {a:'car'}
210
+ x = { 'a' => 'car', 'b' => 'boat'}
211
+ y = { 'a' => 'car' }
210
212
 
211
213
  diff = HashDiff.diff(x, y) do |prefix, obj1, obj2|
212
214
  case prefix
metadata CHANGED
@@ -1,65 +1,75 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: hashdiff
3
- version: !ruby/object:Gem::Version
4
- version: 0.2.1
3
+ version: !ruby/object:Gem::Version
4
+ hash: 19
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 2
9
+ - 2
10
+ version: 0.2.2
5
11
  platform: ruby
6
- authors:
12
+ authors:
7
13
  - Liu Fengyun
8
14
  autorequire:
9
15
  bindir: bin
10
16
  cert_chain: []
11
- date: 2014-07-13 00:00:00.000000000 Z
12
- dependencies:
13
- - !ruby/object:Gem::Dependency
17
+
18
+ date: 2014-10-06 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
14
21
  name: rspec
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ~>
18
- - !ruby/object:Gem::Version
19
- version: '2.0'
20
- type: :development
21
22
  prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
24
26
  - - ~>
25
- - !ruby/object:Gem::Version
26
- version: '2.0'
27
- - !ruby/object:Gem::Dependency
28
- name: yard
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - '>='
32
- - !ruby/object:Gem::Version
33
- version: '0'
27
+ - !ruby/object:Gem::Version
28
+ hash: 3
29
+ segments:
30
+ - 2
31
+ - 0
32
+ version: "2.0"
34
33
  type: :development
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: yard
35
37
  prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - '>='
39
- - !ruby/object:Gem::Version
40
- version: '0'
41
- - !ruby/object:Gem::Dependency
42
- name: bluecloth
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - '>='
46
- - !ruby/object:Gem::Version
47
- version: '0'
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 3
44
+ segments:
45
+ - 0
46
+ version: "0"
48
47
  type: :development
48
+ version_requirements: *id002
49
+ - !ruby/object:Gem::Dependency
50
+ name: bluecloth
49
51
  prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - '>='
53
- - !ruby/object:Gem::Version
54
- version: '0'
55
- description: ' HashDiff is a diff lib to compute the smallest difference between two
56
- hashes. '
57
- email:
52
+ requirement: &id003 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ hash: 3
58
+ segments:
59
+ - 0
60
+ version: "0"
61
+ type: :development
62
+ version_requirements: *id003
63
+ description: " HashDiff is a diff lib to compute the smallest difference between two hashes. "
64
+ email:
58
65
  - liufengyunchina@gmail.com
59
66
  executables: []
67
+
60
68
  extensions: []
69
+
61
70
  extra_rdoc_files: []
62
- files:
71
+
72
+ files:
63
73
  - .gitignore
64
74
  - .rspec
65
75
  - .travis.yml
@@ -84,28 +94,40 @@ files:
84
94
  - spec/hashdiff/util_spec.rb
85
95
  - spec/spec_helper.rb
86
96
  homepage: https://github.com/liufengyun/hashdiff
87
- licenses:
97
+ licenses:
88
98
  - MIT
89
- metadata: {}
90
99
  post_install_message:
91
100
  rdoc_options: []
92
- require_paths:
101
+
102
+ require_paths:
93
103
  - lib
94
- required_ruby_version: !ruby/object:Gem::Requirement
95
- requirements:
96
- - - '>='
97
- - !ruby/object:Gem::Version
104
+ required_ruby_version: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ hash: 57
110
+ segments:
111
+ - 1
112
+ - 8
113
+ - 7
98
114
  version: 1.8.7
99
- required_rubygems_version: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - '>='
102
- - !ruby/object:Gem::Version
103
- version: '0'
115
+ required_rubygems_version: !ruby/object:Gem::Requirement
116
+ none: false
117
+ requirements:
118
+ - - ">="
119
+ - !ruby/object:Gem::Version
120
+ hash: 3
121
+ segments:
122
+ - 0
123
+ version: "0"
104
124
  requirements: []
125
+
105
126
  rubyforge_project:
106
- rubygems_version: 2.0.3
127
+ rubygems_version: 1.8.25
107
128
  signing_key:
108
- specification_version: 4
129
+ specification_version: 3
109
130
  summary: HashDiff is a diff lib to compute the smallest difference between two hashes.
110
131
  test_files: []
132
+
111
133
  has_rdoc:
checksums.yaml DELETED
@@ -1,7 +0,0 @@
1
- ---
2
- SHA1:
3
- metadata.gz: d8b0a6ff22612f26b5bca9a05e0aa2a59903d8ea
4
- data.tar.gz: 239c5cc0d80aad921ab88ae4712c215598b964e5
5
- SHA512:
6
- metadata.gz: f32454eb369913c1ef2da688d843d3fa2f06b7d98d14cbea8a586534735cf0ac548beef2c49608e5d637d0569c08567b11b8bc89a575b01c13ec855be7f51f29
7
- data.tar.gz: dcd6291074a3038274b07ea772f210050dcd8cd448ed0d9b53a47572206bae3d9a64d19b1807194fd10a5ba69e9466999889fc7b190c4e505198c72b9a8887c2