hashdiff 0.3.7 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/lib/hashdiff/util.rb CHANGED
@@ -1,21 +1,22 @@
1
- module HashDiff
1
+ # frozen_string_literal: true
2
2
 
3
+ module Hashdiff
3
4
  # @private
4
5
  #
5
6
  # judge whether two objects are similar
6
- def self.similar?(a, b, options = {})
7
- return compare_values(a, b, options) unless a.is_a?(Array) || a.is_a?(Hash) || b.is_a?(Array) || b.is_a?(Hash)
8
- opts = { :similarity => 0.8 }.merge(options)
7
+ def self.similar?(obja, objb, options = {})
8
+ return compare_values(obja, objb, options) if !options[:comparison] && !any_hash_or_array?(obja, objb)
9
9
 
10
- count_a = count_nodes(a)
11
- count_b = count_nodes(b)
12
- diffs = count_diff diff(a, b, opts)
10
+ count_a = count_nodes(obja)
11
+ count_b = count_nodes(objb)
13
12
 
14
- if count_a + count_b == 0
15
- return true
16
- else
17
- (1 - diffs.to_f/(count_a + count_b).to_f) >= opts[:similarity]
18
- end
13
+ return true if (count_a + count_b).zero?
14
+
15
+ opts = { similarity: 0.8 }.merge!(options)
16
+
17
+ diffs = count_diff diff(obja, objb, opts)
18
+
19
+ (1 - diffs / (count_a + count_b).to_f) >= opts[:similarity]
19
20
  end
20
21
 
21
22
  # @private
@@ -25,7 +26,7 @@ module HashDiff
25
26
  diffs.inject(0) do |sum, item|
26
27
  old_change_count = count_nodes(item[2])
27
28
  new_change_count = count_nodes(item[3])
28
- sum += (old_change_count + new_change_count)
29
+ sum + (old_change_count + new_change_count)
29
30
  end
30
31
  end
31
32
 
@@ -37,9 +38,9 @@ module HashDiff
37
38
 
38
39
  count = 0
39
40
  if obj.is_a?(Array)
40
- obj.each {|e| count += count_nodes(e) }
41
+ obj.each { |e| count += count_nodes(e) }
41
42
  elsif obj.is_a?(Hash)
42
- obj.each {|k, v| count += count_nodes(v) }
43
+ obj.each_value { |v| count += count_nodes(v) }
43
44
  else
44
45
  return 1
45
46
  end
@@ -54,13 +55,13 @@ module HashDiff
54
55
  # @param [String] delimiter Property-string delimiter
55
56
  #
56
57
  # e.g. "a.b[3].c" => ['a', 'b', 3, 'c']
57
- def self.decode_property_path(path, delimiter='.')
58
+ def self.decode_property_path(path, delimiter = '.')
58
59
  path.split(delimiter).inject([]) do |memo, part|
59
60
  if part =~ /^(.*)\[(\d+)\]$/
60
- if $1.size > 0
61
- memo + [$1, $2.to_i]
61
+ if !Regexp.last_match(1).empty?
62
+ memo + [Regexp.last_match(1), Regexp.last_match(2).to_i]
62
63
  else
63
- memo + [$2.to_i]
64
+ memo + [Regexp.last_match(2).to_i]
64
65
  end
65
66
  else
66
67
  memo + [part]
@@ -83,8 +84,8 @@ module HashDiff
83
84
  #
84
85
  # check for equality or "closeness" within given tolerance
85
86
  def self.compare_values(obj1, obj2, options = {})
86
- if (options[:numeric_tolerance].is_a? Numeric) &&
87
- [obj1, obj2].all? { |v| v.is_a? Numeric }
87
+ if options[:numeric_tolerance].is_a?(Numeric) &&
88
+ obj1.is_a?(Numeric) && obj2.is_a?(Numeric)
88
89
  return (obj1 - obj2).abs <= options[:numeric_tolerance]
89
90
  end
90
91
 
@@ -105,10 +106,10 @@ module HashDiff
105
106
  #
106
107
  # check if objects are comparable
107
108
  def self.comparable?(obj1, obj2, strict = true)
108
- [Array, Hash].each do |type|
109
- return true if obj1.is_a?(type) && obj2.is_a?(type)
110
- end
109
+ return true if (obj1.is_a?(Array) || obj1.is_a?(Hash)) && obj2.is_a?(obj1.class)
110
+ return true if (obj2.is_a?(Array) || obj2.is_a?(Hash)) && obj1.is_a?(obj2.class)
111
111
  return true if !strict && obj1.is_a?(Numeric) && obj2.is_a?(Numeric)
112
+
112
113
  obj1.is_a?(obj2.class) && obj2.is_a?(obj1.class)
113
114
  end
114
115
 
@@ -116,23 +117,20 @@ module HashDiff
116
117
  #
117
118
  # try custom comparison
118
119
  def self.custom_compare(method, key, obj1, obj2)
119
- if method
120
- res = method.call(key, obj1, obj2)
121
-
122
- # nil != false here
123
- if res == false
124
- return [['~', key, obj1, obj2]]
125
- elsif res == true
126
- return []
127
- end
128
- end
120
+ return unless method
121
+
122
+ res = method.call(key, obj1, obj2)
123
+
124
+ # nil != false here
125
+ return [['~', key, obj1, obj2]] if res == false
126
+ return [] if res == true
129
127
  end
130
128
 
131
129
  def self.prefix_append_key(prefix, key, opts)
132
130
  if opts[:array_path]
133
131
  prefix + [key]
134
132
  else
135
- prefix.empty? ? "#{key}" : "#{prefix}#{opts[:delimiter]}#{key}"
133
+ prefix.empty? ? key.to_s : "#{prefix}#{opts[:delimiter]}#{key}"
136
134
  end
137
135
  end
138
136
 
@@ -143,4 +141,15 @@ module HashDiff
143
141
  "#{prefix}[#{array_index}]"
144
142
  end
145
143
  end
144
+
145
+ class << self
146
+ private
147
+
148
+ # @private
149
+ #
150
+ # checks if both objects are Arrays or Hashes
151
+ def any_hash_or_array?(obja, objb)
152
+ obja.is_a?(Array) || obja.is_a?(Hash) || objb.is_a?(Array) || objb.is_a?(Hash)
153
+ end
154
+ end
146
155
  end
@@ -1,3 +1,5 @@
1
- module HashDiff
2
- VERSION = '0.3.7'
1
+ # frozen_string_literal: true
2
+
3
+ module Hashdiff
4
+ VERSION = '1.0.1'.freeze
3
5
  end
@@ -1,74 +1,75 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
- describe HashDiff do
4
- it "should be able to best diff" do
5
- a = {'x' => [{'a' => 1, 'c' => 3, 'e' => 5}, {'y' => 3}]}
6
- b = {'x' => [{'a' => 1, 'b' => 2, 'e' => 5}] }
5
+ describe Hashdiff do
6
+ it 'is able to best diff' do
7
+ a = { 'x' => [{ 'a' => 1, 'c' => 3, 'e' => 5 }, { 'y' => 3 }] }
8
+ b = { 'x' => [{ 'a' => 1, 'b' => 2, 'e' => 5 }] }
7
9
 
8
- diff = HashDiff.best_diff(a, b)
9
- diff.should == [["-", "x[0].c", 3], ["+", "x[0].b", 2], ["-", "x[1]", {"y"=>3}]]
10
+ diff = described_class.best_diff(a, b)
11
+ diff.should == [['-', 'x[0].c', 3], ['+', 'x[0].b', 2], ['-', 'x[1]', { 'y' => 3 }]]
10
12
  end
11
13
 
12
- it "should use custom delimiter when provided" do
13
- a = {'x' => [{'a' => 1, 'c' => 3, 'e' => 5}, {'y' => 3}]}
14
- b = {'x' => [{'a' => 1, 'b' => 2, 'e' => 5}] }
14
+ it 'uses custom delimiter when provided' do
15
+ a = { 'x' => [{ 'a' => 1, 'c' => 3, 'e' => 5 }, { 'y' => 3 }] }
16
+ b = { 'x' => [{ 'a' => 1, 'b' => 2, 'e' => 5 }] }
15
17
 
16
- diff = HashDiff.best_diff(a, b, :delimiter => "\t")
17
- diff.should == [["-", "x[0]\tc", 3], ["+", "x[0]\tb", 2], ["-", "x[1]", {"y"=>3}]]
18
+ diff = described_class.best_diff(a, b, delimiter: "\t")
19
+ diff.should == [['-', "x[0]\tc", 3], ['+', "x[0]\tb", 2], ['-', 'x[1]', { 'y' => 3 }]]
18
20
  end
19
21
 
20
- it "should use custom comparison when provided" do
21
- a = {'x' => [{'a' => 'foo', 'c' => 'goat', 'e' => 'snake'}, {'y' => 'baz'}]}
22
- b = {'x' => [{'a' => 'bar', 'b' => 'cow', 'e' => 'puppy'}] }
22
+ it 'uses custom comparison when provided' do
23
+ a = { 'x' => [{ 'a' => 'foo', 'c' => 'goat', 'e' => 'snake' }, { 'y' => 'baz' }] }
24
+ b = { 'x' => [{ 'a' => 'bar', 'b' => 'cow', 'e' => 'puppy' }] }
23
25
 
24
- diff = HashDiff.best_diff(a, b) do |path, obj1, obj2|
26
+ diff = described_class.best_diff(a, b) do |path, obj1, obj2|
25
27
  case path
26
28
  when /^x\[.\]\..$/
27
- obj1.length == obj2.length if obj1 and obj2
29
+ obj1.length == obj2.length if obj1 && obj2
28
30
  end
29
31
  end
30
32
 
31
- diff.should == [["-", "x[0].c", 'goat'], ["+", "x[0].b", 'cow'], ["-", "x[1]", {"y"=>'baz'}]]
33
+ diff.should == [['-', 'x[0].c', 'goat'], ['+', 'x[0].b', 'cow'], ['-', 'x[1]', { 'y' => 'baz' }]]
32
34
  end
33
35
 
34
- it "should be able to best diff array in hash" do
35
- a = {"menu" => {
36
- "id" => "file",
37
- "value" => "File",
38
- "popup" => {
39
- "menuitem" => [
40
- {"value" => "New", "onclick" => "CreateNewDoc()"},
41
- {"value" => "Close", "onclick" => "CloseDoc()"}
36
+ it 'is able to best diff array in hash' do
37
+ a = { 'menu' => {
38
+ 'id' => 'file',
39
+ 'value' => 'File',
40
+ 'popup' => {
41
+ 'menuitem' => [
42
+ { 'value' => 'New', 'onclick' => 'CreateNewDoc()' },
43
+ { 'value' => 'Close', 'onclick' => 'CloseDoc()' }
42
44
  ]
43
45
  }
44
- }}
46
+ } }
45
47
 
46
- b = {"menu" => {
47
- "id" => "file 2",
48
- "value" => "File",
49
- "popup" => {
50
- "menuitem" => [
51
- {"value" => "New1", "onclick" => "CreateNewDoc()"},
52
- {"value" => "Open", "onclick" => "OpenDoc()"},
53
- {"value" => "Close", "onclick" => "CloseDoc()"}
48
+ b = { 'menu' => {
49
+ 'id' => 'file 2',
50
+ 'value' => 'File',
51
+ 'popup' => {
52
+ 'menuitem' => [
53
+ { 'value' => 'New1', 'onclick' => 'CreateNewDoc()' },
54
+ { 'value' => 'Open', 'onclick' => 'OpenDoc()' },
55
+ { 'value' => 'Close', 'onclick' => 'CloseDoc()' }
54
56
  ]
55
57
  }
56
- }}
58
+ } }
57
59
 
58
- diff = HashDiff.best_diff(a, b)
60
+ diff = described_class.best_diff(a, b)
59
61
  diff.should == [
60
62
  ['~', 'menu.id', 'file', 'file 2'],
61
63
  ['~', 'menu.popup.menuitem[0].value', 'New', 'New1'],
62
- ['+', 'menu.popup.menuitem[1]', {"value" => "Open", "onclick" => "OpenDoc()"}]
64
+ ['+', 'menu.popup.menuitem[1]', { 'value' => 'Open', 'onclick' => 'OpenDoc()' }]
63
65
  ]
64
66
  end
65
67
 
66
- it "should be able to have an array_path specified" do
67
- a = {'x' => [{'a' => 1, 'c' => 3, 'e' => 5}, {'y' => 3}]}
68
- b = {'x' => [{'a' => 1, 'b' => 2, 'e' => 5}] }
68
+ it 'is able to have an array_path specified' do
69
+ a = { 'x' => [{ 'a' => 1, 'c' => 3, 'e' => 5 }, { 'y' => 3 }] }
70
+ b = { 'x' => [{ 'a' => 1, 'b' => 2, 'e' => 5 }] }
69
71
 
70
- diff = HashDiff.best_diff(a, b, :array_path => true)
71
- diff.should == [["-", ["x", 0, "c"], 3], ["+", ["x", 0, "b"], 2], ["-", ["x", 1], {"y"=>3}]]
72
+ diff = described_class.best_diff(a, b, array_path: true)
73
+ diff.should == [['-', ['x', 0, 'c'], 3], ['+', ['x', 0, 'b'], 2], ['-', ['x', 1], { 'y' => 3 }]]
72
74
  end
73
-
74
75
  end
@@ -1,60 +1,60 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
- describe HashDiff do
4
- it "should be able to diff two equal array" do
5
+ describe Hashdiff do
6
+ it 'is able to diff two equal array' do
5
7
  a = [1, 2, 3]
6
8
  b = [1, 2, 3]
7
9
 
8
- diff = HashDiff.diff_array_lcs(a, b)
10
+ diff = described_class.diff_array_lcs(a, b)
9
11
  diff.should == []
10
12
  end
11
13
 
12
- it "should be able to diff two arrays with one element in common" do
14
+ it 'is able to diff two arrays with one element in common' do
13
15
  a = [1, 2, 3]
14
16
  b = [1, 8, 7]
15
17
 
16
- diff = HashDiff.diff_array_lcs(a, b)
18
+ diff = described_class.diff_array_lcs(a, b)
17
19
  diff.should == [['-', 2, 3], ['-', 1, 2], ['+', 1, 8], ['+', 2, 7]]
18
20
  end
19
21
 
20
- it "should be able to diff two arrays with nothing in common" do
22
+ it 'is able to diff two arrays with nothing in common' do
21
23
  a = [1, 2]
22
24
  b = []
23
25
 
24
- diff = HashDiff.diff_array_lcs(a, b)
26
+ diff = described_class.diff_array_lcs(a, b)
25
27
  diff.should == [['-', 1, 2], ['-', 0, 1]]
26
28
  end
27
29
 
28
- it "should be able to diff an empty array with an non-empty array" do
30
+ it 'is able to diff an empty array with an non-empty array' do
29
31
  a = []
30
32
  b = [1, 2]
31
33
 
32
- diff = HashDiff.diff_array_lcs(a, b)
34
+ diff = described_class.diff_array_lcs(a, b)
33
35
  diff.should == [['+', 0, 1], ['+', 1, 2]]
34
36
  end
35
37
 
36
- it "should be able to diff two arrays with two elements in common" do
38
+ it 'is able to diff two arrays with two elements in common' do
37
39
  a = [1, 3, 5, 7]
38
40
  b = [2, 3, 7, 5]
39
41
 
40
- diff = HashDiff.diff_array_lcs(a, b)
42
+ diff = described_class.diff_array_lcs(a, b)
41
43
  diff.should == [['-', 0, 1], ['+', 0, 2], ['+', 2, 7], ['-', 4, 7]]
42
44
  end
43
45
 
44
- it "should be able to test two arrays with two common elements in different order" do
46
+ it 'is able to test two arrays with two common elements in different order' do
45
47
  a = [1, 3, 4, 7]
46
48
  b = [2, 3, 7, 5]
47
49
 
48
- diff = HashDiff.diff_array_lcs(a, b)
50
+ diff = described_class.diff_array_lcs(a, b)
49
51
  diff.should == [['-', 0, 1], ['+', 0, 2], ['-', 2, 4], ['+', 3, 5]]
50
52
  end
51
53
 
52
- it "should be able to diff two arrays with similar elements" do
53
- a = [{'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5}, 3]
54
- b = [1, {'a' => 1, 'b' => 2, 'c' => 3, 'e' => 5}]
55
- diff = HashDiff.diff_array_lcs(a, b)
54
+ it 'is able to diff two arrays with similar elements' do
55
+ a = [{ 'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5 }, 3]
56
+ b = [1, { 'a' => 1, 'b' => 2, 'c' => 3, 'e' => 5 }]
57
+ diff = described_class.diff_array_lcs(a, b)
56
58
  diff.should == [['+', 0, 1], ['-', 2, 3]]
57
59
  end
58
-
59
60
  end
60
-
@@ -1,248 +1,255 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
- describe HashDiff do
4
- it "should be able to diff two empty hashes" do
5
- diff = HashDiff.diff({}, {})
5
+ describe Hashdiff do
6
+ it 'is able to diff two empty hashes' do
7
+ diff = described_class.diff({}, {})
6
8
  diff.should == []
7
9
  end
8
10
 
9
- it "should be able to diff an hash with an empty hash" do
11
+ it 'is able to diff an hash with an empty hash' do
10
12
  a = { 'a' => 3, 'b' => 2 }
11
13
  b = {}
12
14
 
13
- diff = HashDiff.diff(a, b)
14
- diff.should == [['-', 'a', 3], ['-', 'b', 2]]
15
+ diff = described_class.diff(a, b)
16
+ expect(diff).to eq([['-', 'a', 3], ['-', 'b', 2]])
15
17
 
16
- diff = HashDiff.diff(b, a)
18
+ diff = described_class.diff(b, a)
17
19
  diff.should == [['+', 'a', 3], ['+', 'b', 2]]
18
20
  end
19
21
 
20
- it "should be able to diff two equal hashes" do
21
- diff = HashDiff.diff({ 'a' => 2, 'b' => 2}, { 'a' => 2, 'b' => 2 })
22
+ it 'is able to diff two equal hashes' do
23
+ diff = described_class.diff({ 'a' => 2, 'b' => 2 }, 'a' => 2, 'b' => 2)
22
24
  diff.should == []
23
25
  end
24
26
 
25
- it "should be able to diff two equal hashes with mixed key types" do
27
+ it 'is able to diff two equal hashes with mixed key types' do
26
28
  a = { 'a' => 1, :b => 1 }
27
- diff = HashDiff.diff(a, a)
29
+ diff = described_class.diff(a, a)
28
30
  diff.should == []
29
31
  end
30
32
 
31
- it "should be able to diff if mixed key types are removed" do
33
+ it 'is able to diff if mixed key types are removed' do
32
34
  a = { 'a' => 1, :b => 1 }
33
35
  b = {}
34
- diff = HashDiff.diff(a, b)
35
- diff.should == [["-", "a", 1], ["-", "b", 1]]
36
+ diff = described_class.diff(a, b)
37
+ diff.should == [['-', 'a', 1], ['-', 'b', 1]]
36
38
  end
37
39
 
38
- it "should be able to diff if mixed key types are added" do
40
+ it 'is able to diff if mixed key types are added' do
39
41
  a = { 'a' => 1, :b => 1 }
40
42
  b = {}
41
- diff = HashDiff.diff(b, a)
42
- diff.should == [["+", "a", 1], ["+", "b", 1]]
43
+ diff = described_class.diff(b, a)
44
+ diff.should == [['+', 'a', 1], ['+', 'b', 1]]
43
45
  end
44
46
 
45
- it "should be able to diff two hashes with equivalent numerics, when strict is false" do
46
- diff = HashDiff.diff({ 'a' => 2.0, 'b' => 2 }, { 'a' => 2, 'b' => 2.0 }, :strict => false)
47
+ it 'is able to diff two hashes with equivalent numerics, when strict is false' do
48
+ diff = described_class.diff({ 'a' => 2.0, 'b' => 2 }, { 'a' => 2, 'b' => 2.0 }, strict: false)
47
49
  diff.should == []
48
50
  end
49
51
 
50
- it "should be able to diff changes in hash value" do
51
- diff = HashDiff.diff({ 'a' => 2, 'b' => 3, 'c' => " hello" }, { 'a' => 2, 'b' => 4, 'c' => "hello" })
52
- diff.should == [['~', 'b', 3, 4], ['~', 'c', " hello", "hello"]]
52
+ it 'ignores string vs symbol differences, when indifferent is true' do
53
+ diff = described_class.diff({ 'a' => 2, :b => 2 }, { :a => 2, 'b' => 2, :c => 3 }, indifferent: true)
54
+ diff.should == [['+', 'c', 3]]
55
+ end
56
+
57
+ it 'is able to diff changes in hash value' do
58
+ diff = described_class.diff({ 'a' => 2, 'b' => 3, 'c' => ' hello' }, 'a' => 2, 'b' => 4, 'c' => 'hello')
59
+ diff.should == [['~', 'b', 3, 4], ['~', 'c', ' hello', 'hello']]
53
60
  end
54
61
 
55
- it "should be able to diff changes in hash value which is array" do
56
- diff = HashDiff.diff({ 'a' => 2, 'b' => [1, 2, 3] }, { 'a' => 2, 'b' => [1, 3, 4]})
62
+ it 'is able to diff changes in hash value which is array' do
63
+ diff = described_class.diff({ 'a' => 2, 'b' => [1, 2, 3] }, 'a' => 2, 'b' => [1, 3, 4])
57
64
  diff.should == [['-', 'b[1]', 2], ['+', 'b[2]', 4]]
58
65
  end
59
66
 
60
- it "should be able to diff changes in hash value which is hash" do
61
- diff = HashDiff.diff({ 'a' => { 'x' => 2, 'y' => 3, 'z' => 4 }, 'b' => { 'x' => 3, 'z' => 45 } },
62
- { 'a' => { 'y' => 3 }, 'b' => { 'y' => 3, 'z' => 30 } })
67
+ it 'is able to diff changes in hash value which is hash' do
68
+ diff = described_class.diff({ 'a' => { 'x' => 2, 'y' => 3, 'z' => 4 }, 'b' => { 'x' => 3, 'z' => 45 } },
69
+ 'a' => { 'y' => 3 }, 'b' => { 'y' => 3, 'z' => 30 })
63
70
  diff.should == [['-', 'a.x', 2], ['-', 'a.z', 4], ['-', 'b.x', 3], ['~', 'b.z', 45, 30], ['+', 'b.y', 3]]
64
71
  end
65
72
 
66
- it "should be able to diff similar objects in array" do
67
- diff = HashDiff.best_diff({ 'a' => [{ 'x' => 2, 'y' => 3, 'z' => 4 }, { 'x' => 11, 'y' => 22, 'z' => 33 }], 'b' => { 'x' => 3, 'z' => 45 } },
68
- { 'a' => [{ 'y' => 3 }, { 'x' => 11, 'z' => 33 }], 'b' => { 'y' => 22 } })
73
+ it 'is able to best diff similar objects in array' do
74
+ diff = described_class.best_diff({ 'a' => [{ 'x' => 2, 'y' => 3, 'z' => 4 }, { 'x' => 11, 'y' => 22, 'z' => 33 }], 'b' => { 'x' => 3, 'z' => 45 } },
75
+ 'a' => [{ 'y' => 3 }, { 'x' => 11, 'z' => 33 }], 'b' => { 'y' => 22 })
69
76
  diff.should == [['-', 'a[0].x', 2], ['-', 'a[0].z', 4], ['-', 'a[1].y', 22], ['-', 'b.x', 3], ['-', 'b.z', 45], ['+', 'b.y', 22]]
70
77
  end
71
78
 
72
- it 'should be able to diff addition of key value pair' do
73
- a = {"a"=>3, "c"=>11, "d"=>45, "e"=>100, "f"=>200}
74
- b = {"a"=>3, "c"=>11, "d"=>45, "e"=>100, "f"=>200, "g"=>300}
79
+ it 'is able to diff addition of key value pair' do
80
+ a = { 'a' => 3, 'c' => 11, 'd' => 45, 'e' => 100, 'f' => 200 }
81
+ b = { 'a' => 3, 'c' => 11, 'd' => 45, 'e' => 100, 'f' => 200, 'g' => 300 }
75
82
 
76
- diff = HashDiff.diff(a, b)
77
- diff.should == [['+', 'g', 300]]
83
+ diff = described_class.diff(a, b)
84
+ expect(diff).to eq([['+', 'g', 300]])
78
85
 
79
- diff = HashDiff.diff(b, a)
86
+ diff = described_class.diff(b, a)
80
87
  diff.should == [['-', 'g', 300]]
81
88
  end
82
89
 
83
- it 'should be able to diff value type changes' do
84
- a = {"a" => 3}
85
- b = {"a" => {"a1" => 1, "a2" => 2}}
90
+ it 'is able to diff value type changes' do
91
+ a = { 'a' => 3 }
92
+ b = { 'a' => { 'a1' => 1, 'a2' => 2 } }
86
93
 
87
- diff = HashDiff.diff(a, b)
88
- diff.should == [['~', 'a', 3, {"a1" => 1, "a2" => 2}]]
94
+ diff = described_class.diff(a, b)
95
+ expect(diff).to eq([['~', 'a', 3, { 'a1' => 1, 'a2' => 2 }]])
89
96
 
90
- diff = HashDiff.diff(b, a)
91
- diff.should == [['~', 'a', {"a1" => 1, "a2" => 2}, 3]]
97
+ diff = described_class.diff(b, a)
98
+ diff.should == [['~', 'a', { 'a1' => 1, 'a2' => 2 }, 3]]
92
99
  end
93
100
 
94
- it "should be able to diff value changes: array <=> []" do
95
- a = {"a" => 1, "b" => [1, 2]}
96
- b = {"a" => 1, "b" => []}
101
+ it 'is able to diff value changes: array <=> []' do
102
+ a = { 'a' => 1, 'b' => [1, 2] }
103
+ b = { 'a' => 1, 'b' => [] }
97
104
 
98
- diff = HashDiff.diff(a, b)
105
+ diff = described_class.diff(a, b)
99
106
  diff.should == [['-', 'b[1]', 2], ['-', 'b[0]', 1]]
100
107
  end
101
108
 
102
- it "should be able to diff value changes: array <=> nil" do
103
- a = {"a" => 1, "b" => [1, 2]}
104
- b = {"a" => 1, "b" => nil}
109
+ it 'is able to diff value changes: array <=> nil' do
110
+ a = { 'a' => 1, 'b' => [1, 2] }
111
+ b = { 'a' => 1, 'b' => nil }
105
112
 
106
- diff = HashDiff.diff(a, b)
107
- diff.should == [["~", "b", [1, 2], nil]]
113
+ diff = described_class.diff(a, b)
114
+ diff.should == [['~', 'b', [1, 2], nil]]
108
115
  end
109
116
 
110
- it "should be able to diff value chagnes: remove array completely" do
111
- a = {"a" => 1, "b" => [1, 2]}
112
- b = {"a" => 1}
117
+ it 'is able to diff value chagnes: remove array completely' do
118
+ a = { 'a' => 1, 'b' => [1, 2] }
119
+ b = { 'a' => 1 }
113
120
 
114
- diff = HashDiff.diff(a, b)
115
- diff.should == [["-", "b", [1, 2]]]
121
+ diff = described_class.diff(a, b)
122
+ diff.should == [['-', 'b', [1, 2]]]
116
123
  end
117
124
 
118
- it "should be able to diff value changes: remove whole hash" do
119
- a = {"a" => 1, "b" => {"b1" => 1, "b2" =>2}}
120
- b = {"a" => 1}
125
+ it 'is able to diff value changes: remove whole hash' do
126
+ a = { 'a' => 1, 'b' => { 'b1' => 1, 'b2' => 2 } }
127
+ b = { 'a' => 1 }
121
128
 
122
- diff = HashDiff.diff(a, b)
123
- diff.should == [["-", "b", {"b1"=>1, "b2"=>2}]]
129
+ diff = described_class.diff(a, b)
130
+ diff.should == [['-', 'b', { 'b1' => 1, 'b2' => 2 }]]
124
131
  end
125
132
 
126
- it "should be able to diff value changes: hash <=> {}" do
127
- a = {"a" => 1, "b" => {"b1" => 1, "b2" =>2}}
128
- b = {"a" => 1, "b" => {}}
133
+ it 'is able to diff value changes: hash <=> {}' do
134
+ a = { 'a' => 1, 'b' => { 'b1' => 1, 'b2' => 2 } }
135
+ b = { 'a' => 1, 'b' => {} }
129
136
 
130
- diff = HashDiff.diff(a, b)
137
+ diff = described_class.diff(a, b)
131
138
  diff.should == [['-', 'b.b1', 1], ['-', 'b.b2', 2]]
132
139
  end
133
140
 
134
- it "should be able to diff value changes: hash <=> nil" do
135
- a = {"a" => 1, "b" => {"b1" => 1, "b2" =>2}}
136
- b = {"a" => 1, "b" => nil}
141
+ it 'is able to diff value changes: hash <=> nil' do
142
+ a = { 'a' => 1, 'b' => { 'b1' => 1, 'b2' => 2 } }
143
+ b = { 'a' => 1, 'b' => nil }
137
144
 
138
- diff = HashDiff.diff(a, b)
139
- diff.should == [["~", "b", {"b1"=>1, "b2"=>2}, nil]]
145
+ diff = described_class.diff(a, b)
146
+ diff.should == [['~', 'b', { 'b1' => 1, 'b2' => 2 }, nil]]
140
147
  end
141
148
 
142
- it "should be able to diff similar objects in array" do
143
- a = [{'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5}, 3]
144
- b = [1, {'a' => 1, 'b' => 2, 'c' => 3, 'e' => 5}]
149
+ it 'is able to diff similar objects in array' do
150
+ a = [{ 'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5 }, 3]
151
+ b = [1, { 'a' => 1, 'b' => 2, 'c' => 3, 'e' => 5 }]
145
152
 
146
- diff = HashDiff.diff(a, b)
153
+ diff = described_class.diff(a, b)
147
154
  diff.should == [['-', '[0].d', 4], ['+', '[0]', 1], ['-', '[2]', 3]]
148
155
  end
149
156
 
150
- it "should be able to diff similar & equal objects in array" do
151
- a = [{'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5}, {'x' => 5, 'y' => 6, 'z' => 3}, 3]
152
- b = [{'a' => 1, 'b' => 2, 'c' => 3, 'e' => 5}, 3]
157
+ it 'is able to diff similar & equal objects in array' do
158
+ a = [{ 'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5 }, { 'x' => 5, 'y' => 6, 'z' => 3 }, 3]
159
+ b = [{ 'a' => 1, 'b' => 2, 'c' => 3, 'e' => 5 }, 3]
153
160
 
154
- diff = HashDiff.diff(a, b)
155
- diff.should == [["-", "[0].d", 4], ["-", "[1]", {"x"=>5, "y"=>6, "z"=>3}]]
161
+ diff = described_class.diff(a, b)
162
+ diff.should == [['-', '[0].d', 4], ['-', '[1]', { 'x' => 5, 'y' => 6, 'z' => 3 }]]
156
163
  end
157
164
 
158
- it "should use custom delimiter when provided" do
159
- a = [{'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5}, {'x' => 5, 'y' => 6, 'z' => 3}, 3]
160
- b = [{'a' => 1, 'b' => 2, 'c' => 3, 'e' => 5}, 3]
165
+ it 'uses custom delimiter when provided' do
166
+ a = [{ 'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5 }, { 'x' => 5, 'y' => 6, 'z' => 3 }, 3]
167
+ b = [{ 'a' => 1, 'b' => 2, 'c' => 3, 'e' => 5 }, 3]
161
168
 
162
- diff = HashDiff.diff(a, b, :similarity => 0.8, :delimiter => "\t")
163
- diff.should == [["-", "[0]\td", 4], ["-", "[1]", {"x"=>5, "y"=>6, "z"=>3}]]
169
+ diff = described_class.diff(a, b, similarity: 0.8, delimiter: "\t")
170
+ diff.should == [['-', "[0]\td", 4], ['-', '[1]', { 'x' => 5, 'y' => 6, 'z' => 3 }]]
164
171
  end
165
172
 
166
173
  context 'when :numeric_tolerance requested' do
167
- it "should be able to diff changes in hash value" do
168
- a = {'a' => 0.558, 'b' => 0.0, 'c' => 0.65, 'd' => 'fin'}
169
- b = {'a' => 0.557, 'b' => 'hats', 'c' => 0.67, 'd' => 'fin'}
174
+ it 'is able to diff changes in hash value' do
175
+ a = { 'a' => 0.558, 'b' => 0.0, 'c' => 0.65, 'd' => 'fin' }
176
+ b = { 'a' => 0.557, 'b' => 'hats', 'c' => 0.67, 'd' => 'fin' }
170
177
 
171
- diff = HashDiff.diff(a, b, :numeric_tolerance => 0.01)
172
- diff.should == [["~", "b", 0.0, 'hats'], ["~", "c", 0.65, 0.67]]
178
+ diff = described_class.diff(a, b, numeric_tolerance: 0.01)
179
+ expect(diff).to eq([['~', 'b', 0.0, 'hats'], ['~', 'c', 0.65, 0.67]])
173
180
 
174
- diff = HashDiff.diff(b, a, :numeric_tolerance => 0.01)
175
- diff.should == [["~", "b", 'hats', 0.0], ["~", "c", 0.67, 0.65]]
181
+ diff = described_class.diff(b, a, numeric_tolerance: 0.01)
182
+ diff.should == [['~', 'b', 'hats', 0.0], ['~', 'c', 0.67, 0.65]]
176
183
  end
177
184
 
178
- it "should be able to diff changes in nested values" do
179
- a = {'a' => {'x' => 0.4, 'y' => 0.338}, 'b' => [13, 68.03]}
180
- b = {'a' => {'x' => 0.6, 'y' => 0.341}, 'b' => [14, 68.025]}
185
+ it 'is able to diff changes in nested values' do
186
+ a = { 'a' => { 'x' => 0.4, 'y' => 0.338 }, 'b' => [13, 68.03] }
187
+ b = { 'a' => { 'x' => 0.6, 'y' => 0.341 }, 'b' => [14, 68.025] }
181
188
 
182
- diff = HashDiff.diff(a, b, :numeric_tolerance => 0.01)
183
- diff.should == [["~", "a.x", 0.4, 0.6], ["-", "b[0]", 13], ["+", "b[0]", 14]]
189
+ diff = described_class.diff(a, b, numeric_tolerance: 0.01)
190
+ expect(diff).to eq([['~', 'a.x', 0.4, 0.6], ['-', 'b[0]', 13], ['+', 'b[0]', 14]])
184
191
 
185
- diff = HashDiff.diff(b, a, :numeric_tolerance => 0.01)
186
- diff.should == [["~", "a.x", 0.6, 0.4], ["-", "b[0]", 14], ["+", "b[0]", 13]]
192
+ diff = described_class.diff(b, a, numeric_tolerance: 0.01)
193
+ diff.should == [['~', 'a.x', 0.6, 0.4], ['-', 'b[0]', 14], ['+', 'b[0]', 13]]
187
194
  end
188
195
  end
189
196
 
190
197
  context 'when :strip requested' do
191
- it "should strip strings before comparing" do
192
- a = { 'a' => " foo", 'b' => "fizz buzz"}
193
- b = { 'a' => "foo", 'b' => "fizzbuzz"}
194
- diff = HashDiff.diff(a, b, :strip => true)
195
- diff.should == [['~', 'b', "fizz buzz", "fizzbuzz"]]
198
+ it 'strips strings before comparing' do
199
+ a = { 'a' => ' foo', 'b' => 'fizz buzz' }
200
+ b = { 'a' => 'foo', 'b' => 'fizzbuzz' }
201
+ diff = described_class.diff(a, b, strip: true)
202
+ diff.should == [['~', 'b', 'fizz buzz', 'fizzbuzz']]
196
203
  end
197
204
 
198
- it "should strip nested strings before comparing" do
199
- a = { 'a' => { 'x' => " foo" }, 'b' => ["fizz buzz", "nerf"] }
200
- b = { 'a' => { 'x' => "foo" }, 'b' => ["fizzbuzz", "nerf"] }
201
- diff = HashDiff.diff(a, b, :strip => true)
202
- diff.should == [['-', 'b[0]', "fizz buzz"], ['+', 'b[0]', "fizzbuzz"]]
205
+ it 'strips nested strings before comparing' do
206
+ a = { 'a' => { 'x' => ' foo' }, 'b' => ['fizz buzz', 'nerf'] }
207
+ b = { 'a' => { 'x' => 'foo' }, 'b' => %w[fizzbuzz nerf] }
208
+ diff = described_class.diff(a, b, strip: true)
209
+ diff.should == [['-', 'b[0]', 'fizz buzz'], ['+', 'b[0]', 'fizzbuzz']]
203
210
  end
204
211
  end
205
212
 
206
213
  context 'when :case_insensitive requested' do
207
- it "should strip strings before comparing" do
208
- a = { 'a' => "Foo", 'b' => "fizz buzz"}
209
- b = { 'a' => "foo", 'b' => "fizzBuzz"}
210
- diff = HashDiff.diff(a, b, :case_insensitive => true)
211
- diff.should == [['~', 'b', "fizz buzz", "fizzBuzz"]]
214
+ it 'strips strings before comparing' do
215
+ a = { 'a' => 'Foo', 'b' => 'fizz buzz' }
216
+ b = { 'a' => 'foo', 'b' => 'fizzBuzz' }
217
+ diff = described_class.diff(a, b, case_insensitive: true)
218
+ diff.should == [['~', 'b', 'fizz buzz', 'fizzBuzz']]
212
219
  end
213
220
 
214
- it "should ignore case on nested strings before comparing" do
215
- a = { 'a' => { 'x' => "Foo" }, 'b' => ["fizz buzz", "nerf"] }
216
- b = { 'a' => { 'x' => "foo" }, 'b' => ["fizzbuzz", "nerf"] }
217
- diff = HashDiff.diff(a, b, :case_insensitive => true)
218
- diff.should == [['-', 'b[0]', "fizz buzz"], ['+', 'b[0]', "fizzbuzz"]]
221
+ it 'ignores case on nested strings before comparing' do
222
+ a = { 'a' => { 'x' => 'Foo' }, 'b' => ['fizz buzz', 'nerf'] }
223
+ b = { 'a' => { 'x' => 'foo' }, 'b' => %w[fizzbuzz nerf] }
224
+ diff = described_class.diff(a, b, case_insensitive: true)
225
+ diff.should == [['-', 'b[0]', 'fizz buzz'], ['+', 'b[0]', 'fizzbuzz']]
219
226
  end
220
227
  end
221
228
 
222
229
  context 'when both :strip and :numeric_tolerance requested' do
223
- it 'should apply filters to proper object types' do
224
- a = { 'a' => " foo", 'b' => 35, 'c' => 'bar', 'd' => 'baz' }
225
- b = { 'a' => "foo", 'b' => 35.005, 'c' => 'bar', 'd' => 18.5}
226
- diff = HashDiff.diff(a, b, :strict => false, :numeric_tolerance => 0.01, :strip => true)
227
- diff.should == [['~', 'd', "baz", 18.5]]
230
+ it 'applies filters to proper object types' do
231
+ a = { 'a' => ' foo', 'b' => 35, 'c' => 'bar', 'd' => 'baz' }
232
+ b = { 'a' => 'foo', 'b' => 35.005, 'c' => 'bar', 'd' => 18.5 }
233
+ diff = described_class.diff(a, b, strict: false, numeric_tolerance: 0.01, strip: true)
234
+ diff.should == [['~', 'd', 'baz', 18.5]]
228
235
  end
229
236
  end
230
237
 
231
- context "when both :strip and :case_insensitive requested" do
232
- it "should apply both filters to strings" do
233
- a = { 'a' => " Foo", 'b' => "fizz buzz"}
234
- b = { 'a' => "foo", 'b' => "fizzBuzz"}
235
- diff = HashDiff.diff(a, b, :case_insensitive => true, :strip => true)
236
- diff.should == [['~', 'b', "fizz buzz", "fizzBuzz"]]
238
+ context 'when both :strip and :case_insensitive requested' do
239
+ it 'applies both filters to strings' do
240
+ a = { 'a' => ' Foo', 'b' => 'fizz buzz' }
241
+ b = { 'a' => 'foo', 'b' => 'fizzBuzz' }
242
+ diff = described_class.diff(a, b, case_insensitive: true, strip: true)
243
+ diff.should == [['~', 'b', 'fizz buzz', 'fizzBuzz']]
237
244
  end
238
245
  end
239
246
 
240
247
  context 'with custom comparison' do
241
- let(:a) { { 'a' => 'car', 'b' => 'boat', 'c' => 'plane'} }
242
- let(:b) { { 'a' => 'bus', 'b' => 'truck', 'c' => ' plan'} }
248
+ let(:a) { { 'a' => 'car', 'b' => 'boat', 'c' => 'plane' } }
249
+ let(:b) { { 'a' => 'bus', 'b' => 'truck', 'c' => ' plan' } }
243
250
 
244
- it 'should compare using proc specified in block' do
245
- diff = HashDiff.diff(a, b) do |prefix, obj1, obj2|
251
+ it 'compares using proc specified in block' do
252
+ diff = described_class.diff(a, b) do |prefix, obj1, obj2|
246
253
  case prefix
247
254
  when /a|b|c/
248
255
  obj1.length == obj2.length
@@ -251,11 +258,11 @@ describe HashDiff do
251
258
  diff.should == [['~', 'b', 'boat', 'truck']]
252
259
  end
253
260
 
254
- it 'should yield added keys' do
255
- x = { 'a' => 'car', 'b' => 'boat'}
261
+ it 'yields added keys' do
262
+ x = { 'a' => 'car', 'b' => 'boat' }
256
263
  y = { 'a' => 'car' }
257
264
 
258
- diff = HashDiff.diff(x, y) do |prefix, obj1, obj2|
265
+ diff = described_class.diff(x, y) do |prefix, _obj1, _obj2|
259
266
  case prefix
260
267
  when /b/
261
268
  true
@@ -264,8 +271,8 @@ describe HashDiff do
264
271
  diff.should == []
265
272
  end
266
273
 
267
- it 'should compare with both proc and :strip when both provided' do
268
- diff = HashDiff.diff(a, b, :strip => true) do |prefix, obj1, obj2|
274
+ it 'compares with both proc and :strip when both provided' do
275
+ diff = described_class.diff(a, b, strip: true) do |prefix, obj1, obj2|
269
276
  case prefix
270
277
  when 'a'
271
278
  obj1.length == obj2.length
@@ -273,65 +280,79 @@ describe HashDiff do
273
280
  end
274
281
  diff.should == [['~', 'b', 'boat', 'truck'], ['~', 'c', 'plane', ' plan']]
275
282
  end
283
+
284
+ it 'compares nested arrays using proc specified in block' do
285
+ a = { a: 'car', b: %w[boat plane] }
286
+ b = { a: 'bus', b: ['truck', ' plan'] }
287
+
288
+ diff = described_class.diff(a, b) do |path, obj1, obj2|
289
+ case path
290
+ when 'b[*]'
291
+ obj1.length == obj2.length
292
+ end
293
+ end
294
+
295
+ expect(diff).to eq [['~', 'a', 'car', 'bus'], ['~', 'b[1]', 'plane', ' plan'], ['-', 'b[0]', 'boat'], ['+', 'b[0]', 'truck']]
296
+ end
276
297
  end
277
298
 
278
299
  context 'when :array_path is true' do
279
- it 'should return the diff path in an array rather than a string' do
300
+ it 'returns the diff path in an array rather than a string' do
280
301
  x = { 'a' => 'foo' }
281
302
  y = { 'a' => 'bar' }
282
- diff = HashDiff.diff(x, y, :array_path => true)
303
+ diff = described_class.diff(x, y, array_path: true)
283
304
 
284
305
  diff.should == [['~', ['a'], 'foo', 'bar']]
285
306
  end
286
307
 
287
- it 'should show array indexes in paths' do
308
+ it 'shows array indexes in paths' do
288
309
  x = { 'a' => [0, 1, 2] }
289
310
  y = { 'a' => [0, 1, 2, 3] }
290
311
 
291
- diff = HashDiff.diff(x, y, :array_path => true)
312
+ diff = described_class.diff(x, y, array_path: true)
292
313
 
293
314
  diff.should == [['+', ['a', 3], 3]]
294
315
  end
295
316
 
296
- it 'should show differences with string and symbol keys' do
317
+ it 'shows differences with string and symbol keys' do
297
318
  x = { 'a' => 'foo' }
298
- y = { :a => 'bar' }
319
+ y = { a: 'bar' }
299
320
 
300
- diff = HashDiff.diff(x, y, :array_path => true)
321
+ diff = described_class.diff(x, y, array_path: true)
301
322
  diff.should == [['-', ['a'], 'foo'], ['+', [:a], 'bar']]
302
323
  end
303
324
 
304
- it 'should support other key types' do
325
+ it 'supports other key types' do
305
326
  time = Time.now
306
327
  x = { time => 'foo' }
307
328
  y = { 0 => 'bar' }
308
329
 
309
- diff = HashDiff.diff(x, y, :array_path => true)
330
+ diff = described_class.diff(x, y, array_path: true)
310
331
  diff.should == [['-', [time], 'foo'], ['+', [0], 'bar']]
311
332
  end
312
333
  end
313
334
 
314
335
  context 'when :use_lcs is false' do
315
- it 'should show items in an array as changed' do
316
- x = [:a, :b]
317
- y = [:c, :d]
318
- diff = HashDiff.diff(x, y, :use_lcs => false)
336
+ it 'shows items in an array as changed' do
337
+ x = %i[a b]
338
+ y = %i[c d]
339
+ diff = described_class.diff(x, y, use_lcs: false)
319
340
 
320
341
  diff.should == [['~', '[0]', :a, :c], ['~', '[1]', :b, :d]]
321
342
  end
322
343
 
323
- it 'should show additions to arrays' do
324
- x = { :a => [0] }
325
- y = { :a => [0, 1] }
326
- diff = HashDiff.diff(x, y, :use_lcs => false)
344
+ it 'shows additions to arrays' do
345
+ x = { a: [0] }
346
+ y = { a: [0, 1] }
347
+ diff = described_class.diff(x, y, use_lcs: false)
327
348
 
328
349
  diff.should == [['+', 'a[1]', 1]]
329
350
  end
330
351
 
331
352
  it 'shows changes to nested arrays' do
332
- x = { :a => [[0, 1]] }
333
- y = { :a => [[1, 2]] }
334
- diff = HashDiff.diff(x, y, :use_lcs => false)
353
+ x = { a: [[0, 1]] }
354
+ y = { a: [[1, 2]] }
355
+ diff = described_class.diff(x, y, use_lcs: false)
335
356
 
336
357
  diff.should == [['~', 'a[0][0]', 0, 1], ['~', 'a[0][1]', 1, 2]]
337
358
  end