hashdiff 0.0.6 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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