hashdiff 0.0.6 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8dbf060a0b7537d436fdf1a5000e37e16227bdbe
4
+ data.tar.gz: 4c2b8998e3f78648c542cc4c8c7a3c95de4a6256
5
+ SHA512:
6
+ metadata.gz: 239b84f71304f154f89ab66c2b654bde48ccdaa3d1ed5748bb89f6449ea7ac8a34749a32f702e0684ea6e070940d4444c38705da413bdf017c6b3a1d6715a516
7
+ data.tar.gz: d20d20328d875a9bd52f6087b3a1cf494534346303e1def382f0a3b836adcb047c99f421a5263d072ebad01830f2b3101962b01ef2eb3bcd9adbf313c3c799c0
data/.gitignore CHANGED
@@ -8,6 +8,8 @@
8
8
  /.bundle
9
9
  /doc
10
10
  /.yardoc
11
+ /Gemfile.lock
11
12
 
12
13
  *.swp
13
14
  *.bak
15
+ *.gem
@@ -2,5 +2,5 @@ language: ruby
2
2
  rvm:
3
3
  - 1.9.2
4
4
  - 1.9.3
5
- - ruby-head
5
+ - 2.0.0
6
6
  script: "bundle exec rake spec"
data/README.md CHANGED
@@ -1,6 +1,4 @@
1
- # HashDiff
2
-
3
- [![Build Status](https://secure.travis-ci.org/liufengyun/hashdiff.png)](http://travis-ci.org/liufengyun/hashdiff)
1
+ # HashDiff [![Build Status](https://secure.travis-ci.org/liufengyun/hashdiff.png)](http://travis-ci.org/liufengyun/hashdiff)
4
2
 
5
3
  HashDiff is a ruby library to compute the smallest difference between two hashes.
6
4
 
@@ -25,10 +23,6 @@ HashDiff answers the question above in an opinionated approach:
25
23
  * It compares Arrays using LCS(longest common subsequence) algorithm.
26
24
  * It recoganize similar Hashes in Array using a similarity value(0 < similarity <= 1).
27
25
 
28
- ## Compatibility
29
-
30
- HashDiff is tested against `1.9.2`, `1.9.3` and `ruby-head`. It should work on other versions as well.
31
-
32
26
  ## Usage
33
27
 
34
28
  If you're using bundler, add following to the Gemfile:
@@ -85,10 +79,22 @@ unpatch example:
85
79
  diff = HashDiff.diff(a, b) # diff two array is OK
86
80
  HashDiff.unpatch!(b, diff).should == a
87
81
 
82
+ ### Options
83
+
84
+ You can specify the delimiter to be something else than the dot. For example:
85
+
86
+ a = {a:{x:2, y:3, z:4}, b:{x:3, z:45}}
87
+ b = {a:{y:3}, b:{y:3, z:30}}
88
+
89
+ diff = HashDiff.diff(a, b, :delimiter => '\t')
90
+ diff.should == [['-', 'a\tx', 2], ['-', 'a\tz', 4], ['-', 'b\tx', 3], ['~', 'b\tz', 45, 30], ['+', 'b\ty', 3]]
91
+
92
+ In cases you have similar hash objects in array, you can pass suitable `:similarity` value instead of the default `0.8`.
93
+
88
94
  ## Contributors
89
95
 
90
- - @liufengyun
91
- - @m-o-e
96
+ - [@liufengyun](https://github.com/liufengyun)
97
+ - [@m-o-e](https://github.com/m-o-e)
92
98
 
93
99
  ## License
94
100
 
@@ -1,5 +1,9 @@
1
1
  # Change Log
2
2
 
3
+ ## v0.1.0 2013-8-25
4
+
5
+ * use options for parameters `:delimiter` and `:similarity` in interfaces
6
+
3
7
  ## v0.0.6 2013-3-2
4
8
 
5
9
  * Add parameter for custom property-path delimiter.
@@ -2,10 +2,12 @@ module HashDiff
2
2
 
3
3
  # Best diff two objects, which tries to generate the smallest change set using different similarity values.
4
4
  #
5
- # HashDiff.best_diff is only meaningful in case of comparing two objects which includes similar objects in array.
5
+ # HashDiff.best_diff is useful in case of comparing two objects which includes similar hashes in array.
6
6
  #
7
7
  # @param [Arrary, Hash] obj1
8
8
  # @param [Arrary, Hash] obj2
9
+ # @param [Hash] options
10
+ # `options` supports `:delimiter`. Default value for `:delimiter` is `.`(dot).
9
11
  #
10
12
  # @return [Array] an array of changes.
11
13
  # e.g. [[ '+', 'a.b', '45' ], [ '-', 'a.c', '5' ], [ '~', 'a.x', '45', '63']]
@@ -17,14 +19,17 @@ module HashDiff
17
19
  # diff.should == [['-', 'x[0].c', 3], ['+', 'x[0].b', 2], ['-', 'x[1].y', 3], ['-', 'x[1]', {}]]
18
20
  #
19
21
  # @since 0.0.1
20
- def self.best_diff(obj1, obj2, delimiter='.')
21
- diffs_1 = diff(obj1, obj2, "", 0.3, delimiter)
22
+ def self.best_diff(obj1, obj2, options = {})
23
+ opts = {similarity: 0.3}.merge!(options)
24
+ diffs_1 = diff(obj1, obj2, opts)
22
25
  count_1 = count_diff diffs_1
23
26
 
24
- diffs_2 = diff(obj1, obj2, "", 0.5, delimiter)
27
+ opts = {similarity: 0.5}.merge!(options)
28
+ diffs_2 = diff(obj1, obj2, opts)
25
29
  count_2 = count_diff diffs_2
26
30
 
27
- diffs_3 = diff(obj1, obj2, "", 0.8, delimiter)
31
+ opts = {similarity: 0.8}.merge!(options)
32
+ diffs_3 = diff(obj1, obj2, opts)
28
33
  count_3 = count_diff diffs_3
29
34
 
30
35
  count, diffs = count_1 < count_2 ? [count_1, diffs_1] : [count_2, diffs_2]
@@ -35,10 +40,12 @@ module HashDiff
35
40
  #
36
41
  # @param [Arrary, Hash] obj1
37
42
  # @param [Arrary, Hash] obj2
38
- # @param [float] similarity A value > 0 and <= 1.
39
- # This parameter should be ignored in common usage.
40
- # Similarity is only meaningful if there're similar objects in arrays. See {best_diff}.
41
- # @param [String] delimiter Delimiter for returned property-string
43
+ # @param [Hash] options
44
+ # `options` can contain `:similarity` or `:delimiter`.
45
+ #
46
+ # `:similarity` should be between (0, 1]. The default value is `0.8`. `:similarity` is meaningful if there're similar hashes in arrays. See {best_diff}.
47
+ #
48
+ # `:delimiter` defaults to `.`(dot).
42
49
  #
43
50
  # @return [Array] an array of changes.
44
51
  # e.g. [[ '+', 'a.b', '45' ], [ '-', 'a.c', '5' ], [ '~', 'a.x', '45', '63']]
@@ -51,41 +58,53 @@ module HashDiff
51
58
  # diff.should == [['-', 'b.b1', 1], ['-', 'b.b2', 2]]
52
59
  #
53
60
  # @since 0.0.1
54
- def self.diff(obj1, obj2, prefix = "", similarity = 0.8, delimiter='.')
61
+ def self.diff(obj1, obj2, options = {})
62
+ opts = {
63
+ :prefix => '',
64
+ :similarity => 0.8,
65
+ :delimiter => '.'
66
+ }
67
+
68
+ opts = opts.merge!(options)
69
+
55
70
  if obj1.nil? and obj2.nil?
56
71
  return []
57
72
  end
58
73
 
59
74
  if obj1.nil?
60
- return [['~', prefix, nil, obj2]]
75
+ return [['~', opts[:prefix], nil, obj2]]
61
76
  end
62
77
 
63
78
  if obj2.nil?
64
- return [['~', prefix, obj1, nil]]
79
+ return [['~', opts[:prefix], obj1, nil]]
65
80
  end
66
81
 
67
82
  if !(obj1.is_a?(Array) and obj2.is_a?(Array)) and !(obj1.is_a?(Hash) and obj2.is_a?(Hash)) and !(obj1.is_a?(obj2.class) or obj2.is_a?(obj1.class))
68
- return [['~', prefix, obj1, obj2]]
83
+ return [['~', opts[:prefix], obj1, obj2]]
69
84
  end
70
85
 
71
86
  result = []
72
87
  if obj1.is_a?(Array)
73
- changeset = diff_array(obj1, obj2, similarity) do |lcs|
88
+ changeset = diff_array(obj1, obj2, opts[:similarity]) do |lcs|
74
89
  # use a's index for similarity
75
90
  lcs.each do |pair|
76
- result.concat(diff(obj1[pair[0]], obj2[pair[1]], "#{prefix}[#{pair[0]}]", similarity, delimiter))
91
+ result.concat(diff(obj1[pair[0]], obj2[pair[1]], opts.merge(prefix: "#{opts[:prefix]}[#{pair[0]}]")))
77
92
  end
78
93
  end
79
94
 
80
95
  changeset.each do |change|
81
96
  if change[0] == '-'
82
- result << ['-', "#{prefix}[#{change[1]}]", change[2]]
97
+ result << ['-', "#{opts[:prefix]}[#{change[1]}]", change[2]]
83
98
  elsif change[0] == '+'
84
- result << ['+', "#{prefix}[#{change[1]}]", change[2]]
99
+ result << ['+', "#{opts[:prefix]}[#{change[1]}]", change[2]]
85
100
  end
86
101
  end
87
102
  elsif obj1.is_a?(Hash)
88
- prefix = prefix.empty? ? "" : "#{prefix}#{delimiter}"
103
+ if opts[:prefix].empty?
104
+ prefix = ""
105
+ else
106
+ prefix = "#{opts[:prefix]}#{opts[:delimiter]}"
107
+ end
89
108
 
90
109
  deleted_keys = []
91
110
  common_keys = []
@@ -102,7 +121,7 @@ module HashDiff
102
121
  deleted_keys.each {|k| result << ['-', "#{prefix}#{k}", obj1[k]] }
103
122
 
104
123
  # recursive comparison for common keys
105
- common_keys.each {|k| result.concat(diff(obj1[k], obj2[k], "#{prefix}#{k}", similarity, delimiter)) }
124
+ common_keys.each {|k| result.concat(diff(obj1[k], obj2[k], opts.merge(prefix: "#{prefix}#{k}"))) }
106
125
 
107
126
  # added properties
108
127
  obj2.each do |k, v|
@@ -112,7 +131,7 @@ module HashDiff
112
131
  end
113
132
  else
114
133
  return [] if obj1 == obj2
115
- return [['~', prefix, obj1, obj2]]
134
+ return [['~', opts[:prefix], obj1, obj2]]
116
135
  end
117
136
 
118
137
  result
@@ -7,12 +7,15 @@ module HashDiff
7
7
  #
8
8
  # @param [Hash, Array] obj the object to be patchted, can be an Array of a Hash
9
9
  # @param [Array] changes e.g. [[ '+', 'a.b', '45' ], [ '-', 'a.c', '5' ], [ '~', 'a.x', '45', '63']]
10
- # @param [String] delimiter Property-string delimiter
10
+ # @param [Hash] options
11
+ # `options` supports `:delimiter`. Default value for `:delimiter` is `.`(dot).
11
12
  #
12
13
  # @return the object after patch
13
14
  #
14
15
  # @since 0.0.1
15
- def self.patch!(obj, changes, delimiter='.')
16
+ def self.patch!(obj, changes, options = {})
17
+ delimiter = options[:delimiter] || '.'
18
+
16
19
  changes.each do |change|
17
20
  parts = decode_property_path(change[1], delimiter)
18
21
  last_part = parts.last
@@ -43,12 +46,15 @@ module HashDiff
43
46
  #
44
47
  # @param [Hash, Array] obj the object to be unpatchted, can be an Array of a Hash
45
48
  # @param [Array] changes e.g. [[ '+', 'a.b', '45' ], [ '-', 'a.c', '5' ], [ '~', 'a.x', '45', '63']]
46
- # @param [String] delimiter Property-string delimiter
49
+ # @param [Hash] options
50
+ # `options` supports `:delimiter`. Default value for `:delimiter` is `.`(dot).
47
51
  #
48
52
  # @return the object after unpatch
49
53
  #
50
54
  # @since 0.0.1
51
- def self.unpatch!(obj, changes, delimiter='.')
55
+ def self.unpatch!(obj, changes, options = {})
56
+ delimiter = options[:delimiter] || '.'
57
+
52
58
  changes.reverse_each do |change|
53
59
  parts = decode_property_path(change[1], delimiter)
54
60
  last_part = parts.last
@@ -6,7 +6,7 @@ module HashDiff
6
6
  def self.similar?(a, b, similarity = 0.8)
7
7
  count_a = count_nodes(a)
8
8
  count_b = count_nodes(b)
9
- diffs = count_diff diff(a, b, "", similarity)
9
+ diffs = count_diff diff(a, b, :similarity => similarity)
10
10
 
11
11
  if count_a + count_b == 0
12
12
  return true
@@ -1,3 +1,3 @@
1
1
  module HashDiff
2
- VERSION = '0.0.6'
2
+ VERSION = '0.1.0'
3
3
  end
@@ -13,11 +13,10 @@ describe HashDiff do
13
13
  a = {'x' => [{'a' => 1, 'c' => 3, 'e' => 5}, {'y' => 3}]}
14
14
  b = {'x' => [{'a' => 1, 'b' => 2, 'e' => 5}] }
15
15
 
16
- diff = HashDiff.best_diff(a, b, "\t")
16
+ diff = HashDiff.best_diff(a, b, :delimiter => "\t")
17
17
  diff.should == [["-", "x[0]\tc", 3], ["+", "x[0]\tb", 2], ["-", "x[1]", {"y"=>3}]]
18
18
  end
19
19
 
20
-
21
20
  it "should be able to best diff array in hash" do
22
21
  a = {"menu" => {
23
22
  "id" => "file",
@@ -127,7 +127,7 @@ describe HashDiff do
127
127
  a = [{'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5}, {'x' => 5, 'y' => 6, 'z' => 3}, 3]
128
128
  b = [{'a' => 1, 'b' => 2, 'c' => 3, 'e' => 5}, 3]
129
129
 
130
- diff = HashDiff.diff(a, b, "", 0.8, "\t")
130
+ diff = HashDiff.diff(a, b, similarity: 0.8, delimiter: "\t")
131
131
  diff.should == [["-", "[0]\td", 4], ["-", "[1]", {"x"=>5, "y"=>6, "z"=>3}]]
132
132
  end
133
133
 
@@ -134,4 +134,3 @@ describe HashDiff do
134
134
  end
135
135
 
136
136
  end
137
-
@@ -11,7 +11,6 @@ describe HashDiff do
11
11
  decoded.should == ['a', 'b', 0, 'c', 'city', 5]
12
12
  end
13
13
 
14
-
15
14
  it "should be able to tell similiar hash" do
16
15
  a = {'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5}
17
16
  b = {'a' => 1, 'b' => 2, 'c' => 3, 'e' => 5}
metadata CHANGED
@@ -1,20 +1,18 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hashdiff
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
5
- prerelease:
4
+ version: 0.1.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Liu Fengyun
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-03-03 00:00:00.000000000 Z
11
+ date: 2013-08-25 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: rspec
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
17
  - - ~>
20
18
  - !ruby/object:Gem::Version
@@ -22,7 +20,6 @@ dependencies:
22
20
  type: :development
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
24
  - - ~>
28
25
  - !ruby/object:Gem::Version
@@ -30,37 +27,33 @@ dependencies:
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: yard
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ! '>='
31
+ - - '>='
36
32
  - !ruby/object:Gem::Version
37
33
  version: '0'
38
34
  type: :development
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ! '>='
38
+ - - '>='
44
39
  - !ruby/object:Gem::Version
45
40
  version: '0'
46
41
  - !ruby/object:Gem::Dependency
47
42
  name: bluecloth
48
43
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
44
  requirements:
51
- - - ! '>='
45
+ - - '>='
52
46
  - !ruby/object:Gem::Version
53
47
  version: '0'
54
48
  type: :development
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
51
  requirements:
59
- - - ! '>='
52
+ - - '>='
60
53
  - !ruby/object:Gem::Version
61
54
  version: '0'
62
- description: ! ' HashDiff is a diff lib to compute the smallest difference between
63
- two hashes. '
55
+ description: ' HashDiff is a diff lib to compute the smallest difference between two
56
+ hashes. '
64
57
  email:
65
58
  - liufengyunchina@gmail.com
66
59
  executables: []
@@ -72,7 +65,6 @@ files:
72
65
  - .travis.yml
73
66
  - .yardopts
74
67
  - Gemfile
75
- - Gemfile.lock
76
68
  - LICENSE
77
69
  - README.md
78
70
  - Rakefile
@@ -93,27 +85,26 @@ files:
93
85
  - spec/spec_helper.rb
94
86
  homepage: https://github.com/liufengyun/hashdiff
95
87
  licenses: []
88
+ metadata: {}
96
89
  post_install_message:
97
90
  rdoc_options: []
98
91
  require_paths:
99
92
  - lib
100
93
  required_ruby_version: !ruby/object:Gem::Requirement
101
- none: false
102
94
  requirements:
103
- - - ! '>='
95
+ - - '>='
104
96
  - !ruby/object:Gem::Version
105
97
  version: 1.8.7
106
98
  required_rubygems_version: !ruby/object:Gem::Requirement
107
- none: false
108
99
  requirements:
109
- - - ! '>='
100
+ - - '>='
110
101
  - !ruby/object:Gem::Version
111
102
  version: '0'
112
103
  requirements: []
113
104
  rubyforge_project:
114
- rubygems_version: 1.8.24
105
+ rubygems_version: 2.0.3
115
106
  signing_key:
116
- specification_version: 3
107
+ specification_version: 4
117
108
  summary: HashDiff is a diff lib to compute the smallest difference between two hashes.
118
109
  test_files: []
119
110
  has_rdoc:
@@ -1,30 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- hashdiff (0.0.5)
5
-
6
- GEM
7
- remote: http://rubygems.org/
8
- specs:
9
- bluecloth (2.2.0)
10
- diff-lcs (1.1.3)
11
- rake (0.9.2.2)
12
- rspec (2.10.0)
13
- rspec-core (~> 2.10.0)
14
- rspec-expectations (~> 2.10.0)
15
- rspec-mocks (~> 2.10.0)
16
- rspec-core (2.10.1)
17
- rspec-expectations (2.10.0)
18
- diff-lcs (~> 1.1.3)
19
- rspec-mocks (2.10.1)
20
- yard (0.8.1)
21
-
22
- PLATFORMS
23
- ruby
24
-
25
- DEPENDENCIES
26
- bluecloth
27
- hashdiff!
28
- rake
29
- rspec (~> 2.0)
30
- yard