hashdiff 0.2.1 → 0.2.2

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.
@@ -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