hash_deep_diff 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ddbaa8e8f12ba99330973c609c00ab710e9fa39b369797b80dd46f24aa6740e1
4
- data.tar.gz: 6a5954a960ca0876cdb9e28f3e535be687de5596ed07be61581102b75b178ab4
3
+ metadata.gz: dc574fc78f743f8b629ecbb87baebea7e75789d99401f7e54691ad02469572ec
4
+ data.tar.gz: 0f378780b1f08173779e3684a8d42361c0532411c7972952a626bc3e4a0bebb0
5
5
  SHA512:
6
- metadata.gz: af66a50e5a7eb848c96b757e8e37a4d767868de6fd96ebfd4f528085111e2fe1c9e39215b8514d534d33f94cfc4c024c5c2bba1813acad729fa906e18eee796a
7
- data.tar.gz: 358e25298ee3c42ea469e44113fe62935ec8f564c4111c52e170bd25764d99cc4b71c42d154689ad2a9c54ff21f9359dad57cfbd450677853eb60655b90aecf4
6
+ metadata.gz: dd12f9bc333f1a8ab3d4967bcdaeee7eac9cf66a97883a122cfa3f3e831165da62cce4b4dadf0e5e3c750cc43dcd59629b20c279d215b42ebd2d6fd65ebcc497
7
+ data.tar.gz: 64b6e8dbf48807f23ca32e84cfec991e14ff56ffda7bb65b71a1db3bc7d800ca0f94f00038e49dc1cd2bd30b84ad6c05496de599038d97960dece9f827cde4fb
data/CHANGELOG.md CHANGED
@@ -0,0 +1 @@
1
+ Changes will be recorded for version 1.0.0 and later
data/README.md CHANGED
@@ -5,7 +5,9 @@ Status](https://img.shields.io/github/workflow/status/bpohoriletz/hash_deep_diff
5
5
  ![GitHub](https://img.shields.io/github/license/bpohoriletz/hash_deep_diff)
6
6
 
7
7
 
8
- Find the exact difference between two Hash objects and build a report to visualize it
8
+ Find the exact difference between two Hash objects and build a report to visualize it. Works for other objects too but why would you do that :/
9
+
10
+ Alternative solutions [hashdiff by liufengyun](https://github.com/liufengyun/hashdiff) and [hash_hdiff by CodingZeal](https://github.com/CodingZeal/hash_diff)
9
11
 
10
12
  ## Installation
11
13
 
@@ -37,7 +39,7 @@ HashDeepDiff::Comparison.new(left, right).report
37
39
  + left[a] = b
38
40
  ```
39
41
  please see [Documentation](https://rdoc.info/gems/hash_deep_diff/HashDeepDiff/Comparison) for
40
- more information
42
+ more information or [Reporting test](https://github.com/bpohoriletz/hash_deep_diff/blob/a525d239189b0310aec3741dfc4862834805252d/test/integration/locales/test_uk_ru.rb#L59)
41
43
 
42
44
  ## Customization
43
45
 
@@ -49,6 +49,7 @@ Gem::Specification.new do |spec|
49
49
  spec.add_development_dependency 'minitest-focus', '~> 1.3.1'
50
50
  spec.add_development_dependency 'minitest-reporters', '~> 1.5.0'
51
51
  spec.add_development_dependency 'naught', '~> 1.1.0'
52
+ spec.add_development_dependency 'pry-byebug', '~> 3.9.0'
52
53
  spec.add_development_dependency 'rake', '~> 10.5.0'
53
54
  spec.add_development_dependency 'rubocop', '~> 1.26.1'
54
55
  spec.add_development_dependency 'rubocop-minitest', '~> 0.18.0'
@@ -63,6 +63,7 @@ module HashDeepDiff
63
63
  def left(key = NO_VALUE)
64
64
  return NO_VALUE if @left == NO_VALUE
65
65
  return @left if key == NO_VALUE
66
+ return @left unless left.respond_to?(:to_hash)
66
67
 
67
68
  @left[key] || NO_VALUE
68
69
  end
@@ -71,6 +72,7 @@ module HashDeepDiff
71
72
  def right(key = NO_VALUE)
72
73
  return NO_VALUE if @right == NO_VALUE
73
74
  return @right if key == NO_VALUE
75
+ return @right unless right.respond_to?(:to_hash)
74
76
 
75
77
  @right[key] || NO_VALUE
76
78
  end
@@ -98,22 +100,19 @@ module HashDeepDiff
98
100
  common_keys.each_with_object([]) do |key, memo|
99
101
  next if values_equal?(key)
100
102
 
101
- memo << delta(key: key)
102
- end
103
+ memo.append(delta(key: key))
104
+ end.flatten
103
105
  end
104
106
 
105
107
  # depending on circumstances will return necessary comparisons
106
108
  # @return [Array<HashDeepDiff::Delta>]
107
109
  def inward_comparison(complex_delta)
108
110
  if complex_delta.partial?
109
- [
110
- complex_delta.placebo,
111
- comparison(delta: complex_delta, modifier: :right).diff,
112
- comparison(delta: complex_delta, modifier: :left).diff
113
- ].compact.flatten
114
- # TOFIX add test an drop flatten
111
+ complex_delta.placebo +
112
+ comparison(delta: complex_delta, modifier: :addition).map(&:diff).flatten +
113
+ comparison(delta: complex_delta, modifier: :deletion).map(&:diff).flatten
115
114
  else
116
- comparison(delta: complex_delta).diff
115
+ comparison(delta: complex_delta).map(&:diff).flatten
117
116
  end
118
117
  end
119
118
 
@@ -16,29 +16,45 @@ module HashDeepDiff
16
16
  attr_reader :change_key
17
17
 
18
18
  # an indication that nested Hash was deleted/added
19
- # @return [HashDeepDiff::Delta, NilClass]
19
+ # @return [Array<HashDeepDiff::Delta>]
20
20
  def placebo
21
- return nil unless partial?
21
+ placebo = simple_left? ? { left: NO_VALUE, right: placebo_elment } : { left: placebo_elment, right: NO_VALUE }
22
22
 
23
- placebo = simple_left? ? { left: NO_VALUE, right: {} } : { left: {}, right: NO_VALUE }
23
+ [self.class.new(change_key: change_key, value: placebo)]
24
+ end
25
+
26
+ # true if any value is an +Array+ with hashes
27
+ # @return [TrueClass, FalseClass]
28
+ def complex?
29
+ complex_left? || complex_right?
30
+ end
31
+
32
+ # true if right part is an +Array+ with hashes
33
+ # @return [TrueClass, FalseClass]
34
+ def complex_right?
35
+ right.respond_to?(:to_ary) && right.any? { |el| el.respond_to?(:to_hash) }
36
+ end
24
37
 
25
- self.class.new(change_key: change_key, value: placebo)
38
+ # true if left part is an +Array+ with hashes
39
+ # @return [TrueClass, FalseClass]
40
+ def complex_left?
41
+ left.respond_to?(:to_ary) && left.any? { |el| el.respond_to?(:to_hash) }
26
42
  end
27
43
 
28
44
  # true if at least one of the values is a Hash
29
- # @return [Bool]
45
+ # @return [TrueClass, FalseClass]
30
46
  def partial?
31
- !composite? && !simple?
47
+ !composite? && !simple? && !complex_left? && !complex_right?
32
48
  end
33
49
 
34
50
  # true if both valus are Hashes
35
- # @return [Bool]
51
+ # @return [TrueClass, FalseClass]
36
52
  def composite?
37
53
  !simple_left? && !simple_right?
38
54
  end
39
55
 
40
56
  # true if none of the values is a Hash
41
- # @return [Bool]
57
+ # @return [TrueClass, FalseClass]
42
58
  def simple?
43
59
  simple_left? && simple_right?
44
60
  end
@@ -76,16 +92,24 @@ module HashDeepDiff
76
92
  @change_key = change_key
77
93
  end
78
94
 
79
- # Returns true if left value has no nested Hashes
80
- # @return [Bool]
95
+ # an indication of added/removed nested Hash
96
+ # @return [Array, Hash]
97
+ def placebo_elment
98
+ return [{}] if complex_left? || complex_right?
99
+
100
+ return {}
101
+ end
102
+
103
+ # true if left value has no nested Hashes
104
+ # @return [TrueClass, FalseClass]
81
105
  def simple_left?
82
- !left.respond_to?(:to_hash)
106
+ !left.respond_to?(:to_hash) && !complex_left?
83
107
  end
84
108
 
85
- # Returns true if right value has no nested Hashes
86
- # @return [Bool]
109
+ # true if right value has no nested Hashes
110
+ # @return [TrueClass, FalseClass]
87
111
  def simple_right?
88
- !right.respond_to?(:to_hash)
112
+ !right.respond_to?(:to_hash) && !complex_right?
89
113
  end
90
114
  end
91
115
  end
@@ -8,50 +8,83 @@ module HashDeepDiff
8
8
  # Factory for {HashDeepDiff::Comparison}
9
9
  class Comparison
10
10
  extend Forwardable
11
- def_delegators :delta, :left, :right, :change_key
11
+
12
+ def_delegators :delta, :left, :right, :change_key, :complex?, :complex_left?, :complex_right?
12
13
 
13
14
  # factory function
14
- # @return [Comparison]
15
- def comparison(delta:, modifier: nil)
15
+ # @return [HashDeepDiff::Comparison]
16
+ def comparison(delta:, modifier: :change)
16
17
  @delta = delta
17
18
 
18
- case modifier
19
- when nil
20
- full_compare
21
- when :left
22
- compare_left
23
- when :right
24
- compare_right
19
+ fragments(modifier).map do |(left, right, change_key)|
20
+ HashDeepDiff::Comparison.new(left, right, change_key,
21
+ delta_engine: delta.class,
22
+ reporting_engine: reporting_engine)
25
23
  end
26
24
  end
27
25
 
28
26
  private
29
27
 
28
+ # @!attribute [r] reporting_engine
29
+ # @return [HashDeepDiff::Reports::Base] descendant of
30
+ # @!attribute [r] delta
31
+ # @return [HashDeepDiff::Delta]
30
32
  attr_reader :reporting_engine, :delta
31
33
 
32
34
  def initialize(reporting_engine:)
33
35
  @reporting_engine = reporting_engine
34
36
  end
35
37
 
36
- # compare two hashes
37
- def full_compare
38
- HashDeepDiff::Comparison.new(left, right, change_key,
39
- delta_engine: delta.class,
40
- reporting_engine: reporting_engine)
38
+ # entities for further comparison
39
+ # @return [Array]
40
+ def fragments(mode)
41
+ case mode
42
+ when :change
43
+ return [[value_left, value_right, change_key]] unless complex?
44
+
45
+ [[value_left, value_right, change_key + ['...']],
46
+ [nesting_left, nesting_right, change_key + ['{}']]]
47
+ when :deletion
48
+ [[value_left, NO_VALUE, change_key]]
49
+ when :addition
50
+ [[NO_VALUE, value_right, change_key]]
51
+ end
41
52
  end
42
53
 
43
- # compare Hash with nothing (deletion)
44
- def compare_left
45
- HashDeepDiff::Comparison.new(left, NO_VALUE, change_key,
46
- delta_engine: delta.class,
47
- reporting_engine: reporting_engine)
54
+ # original value without nested hashes
55
+ # @return [Object]
56
+ def value_left
57
+ return left unless left.respond_to?(:to_ary)
58
+
59
+ left.reject { |el| el.respond_to?(:to_hash) }
48
60
  end
49
61
 
50
- # compare nothing with Hash (addition)
51
- def compare_right
52
- HashDeepDiff::Comparison.new(NO_VALUE, right, change_key,
53
- delta_engine: delta.class,
54
- reporting_engine: reporting_engine)
62
+ # changed value without nested hashes
63
+ # @return [Object]
64
+ def value_right
65
+ return right unless right.respond_to?(:to_ary)
66
+
67
+ right.reject { |el| el.respond_to?(:to_hash) }
68
+ end
69
+
70
+ # nested hashes from original value
71
+ # @return [Array<Hash>]
72
+ def nesting_left
73
+ return NO_VALUE unless complex_left?
74
+
75
+ left
76
+ .select { |el| el.respond_to?(:to_hash) }
77
+ .each_with_object({}) { |el, memo| memo.merge!(el) }
78
+ end
79
+
80
+ # nested hashes from changed value
81
+ # @return [Array<Hash>]
82
+ def nesting_right
83
+ return NO_VALUE unless complex_right?
84
+
85
+ right
86
+ .select { |el| el.respond_to?(:to_hash) }
87
+ .each_with_object({}) { |el, memo| memo.merge!(el) }
55
88
  end
56
89
  end
57
90
  end
@@ -19,6 +19,13 @@ module HashDeepDiff
19
19
 
20
20
  private
21
21
 
22
+ # @!attribute [r] old_val
23
+ # @return [Object] original value
24
+ # @!attribute [r] new_val
25
+ # @return [Object] replacement of the original value
26
+ # @!attribute [r] change_key
27
+ # @return [Array<Object>] subset of keys from original Hashes to fetch reported values
28
+ # (is empty for top-level comparison)
22
29
  attr_reader :old_val, :new_val, :change_key
23
30
 
24
31
  # @param [Delta] delta diff to report
@@ -9,20 +9,42 @@ module HashDeepDiff
9
9
  class Diff < Base
10
10
  private
11
11
 
12
- # old value
12
+ # line of the report with deleted value
13
13
  # @return [String]
14
14
  def original
15
15
  return '' if old_val == NO_VALUE
16
+ return "#{deletion}#{path} = #{old_val}\n" unless array_to_array?
17
+ return '' if array_deletion.empty?
16
18
 
17
- return "#{deletion}#{path} = #{old_val}\n"
19
+ "#{deletion}#{path} = #{array_deletion}\n"
18
20
  end
19
21
 
20
- # new value
22
+ # line of the report with added value
21
23
  # @return [String]
22
24
  def replacement
23
25
  return '' if new_val == NO_VALUE
26
+ return "#{addition}#{path} = #{new_val}\n" unless array_to_array?
27
+ return '' if array_addition.empty?
24
28
 
25
- return "#{addition}#{path} = #{new_val}\n"
29
+ "#{addition}#{path} = #{array_addition}\n"
30
+ end
31
+
32
+ # returns true if original value and replacement are instances of +Array+
33
+ # @return Bool
34
+ def array_to_array?
35
+ old_val.instance_of?(Array) && new_val.instance_of?(Array)
36
+ end
37
+
38
+ # added elemnts of array
39
+ # @return [Array]
40
+ def array_addition
41
+ new_val - old_val
42
+ end
43
+
44
+ # added elemnts of array
45
+ # @return [Array]
46
+ def array_deletion
47
+ old_val - new_val
26
48
  end
27
49
 
28
50
  # Visual representation of keys from compared objects needed to fetch the compared values
@@ -2,5 +2,5 @@
2
2
 
3
3
  module HashDeepDiff
4
4
  # Version of a gem
5
- VERSION = '0.6.0'
5
+ VERSION = '0.7.0'
6
6
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hash_deep_diff
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bohdan Pohorilets
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-04-25 00:00:00.000000000 Z
11
+ date: 2022-05-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -136,6 +136,20 @@ dependencies:
136
136
  - - "~>"
137
137
  - !ruby/object:Gem::Version
138
138
  version: 1.1.0
139
+ - !ruby/object:Gem::Dependency
140
+ name: pry-byebug
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: 3.9.0
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: 3.9.0
139
153
  - !ruby/object:Gem::Dependency
140
154
  name: rake
141
155
  requirement: !ruby/object:Gem::Requirement