hash_deep_diff 0.7.0 → 0.8.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dc574fc78f743f8b629ecbb87baebea7e75789d99401f7e54691ad02469572ec
4
- data.tar.gz: 0f378780b1f08173779e3684a8d42361c0532411c7972952a626bc3e4a0bebb0
3
+ metadata.gz: 0e7ceeb1c2e935cc4b6c9d27e6d718f63f627d3adeba269df367c37464f3e9c0
4
+ data.tar.gz: 00053a3c87a26ea7dff3513594c6fb85e1235be3c341bc58f30d4934faa3de57
5
5
  SHA512:
6
- metadata.gz: dd12f9bc333f1a8ab3d4967bcdaeee7eac9cf66a97883a122cfa3f3e831165da62cce4b4dadf0e5e3c750cc43dcd59629b20c279d215b42ebd2d6fd65ebcc497
7
- data.tar.gz: 64b6e8dbf48807f23ca32e84cfec991e14ff56ffda7bb65b71a1db3bc7d800ca0f94f00038e49dc1cd2bd30b84ad6c05496de599038d97960dece9f827cde4fb
6
+ metadata.gz: 612c398c02060fd908f449ac44893a8a81d33f3c1f13ec86bb3042d748034f18a20fbd99559c211af58e5f70d77d0b107fda0fae6cb2be3a1f94e1e0299c0f2e
7
+ data.tar.gz: c63d6e0ddad970dce331a5460981916b821805a8a3fe8b95f5ab6ea73a029942091acdf6b9681da533630fd6da38440749419d25436979e07cd15da5a2020658
data/.rubocop.yml CHANGED
@@ -10,6 +10,7 @@ AllCops:
10
10
  - '.git/**/*'
11
11
  - '.bundle/**/*'
12
12
  - 'bin/*'
13
+ TargetRubyVersion: 2.6.1
13
14
 
14
15
  Style/RedundantReturn:
15
16
  Enabled: false
@@ -18,3 +19,9 @@ Metrics/BlockLength:
18
19
  Exclude:
19
20
  - 'test/**/test_*.rb'
20
21
  - '*.gemspec'
22
+ Style/YodaCondition:
23
+ EnforcedStyle: require_for_all_comparison_operators
24
+
25
+ Minitest/AssertEmptyLiteral:
26
+ Exclude:
27
+ - 'test/unit/test_change_key.rb'
data/README.md CHANGED
@@ -7,7 +7,7 @@ Status](https://img.shields.io/github/workflow/status/bpohoriletz/hash_deep_diff
7
7
 
8
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
9
 
10
- Alternative solutions [hashdiff by liufengyun](https://github.com/liufengyun/hashdiff) and [hash_hdiff by CodingZeal](https://github.com/CodingZeal/hash_diff)
10
+ Alternative solutions [hashdiff](https://github.com/liufengyun/hashdiff) by liufengyun and [hash_diff](https://github.com/CodingZeal/hash_diff) by CodingZeal
11
11
 
12
12
  ## Installation
13
13
 
@@ -26,21 +26,93 @@ Or install it yourself as:
26
26
  $ gem install hash_deep_diff
27
27
 
28
28
  ## Usage
29
- Basic example
29
+ ### Basic
30
30
 
31
31
  ```ruby
32
32
  left = { a: :a }
33
33
  right = { a: :b }
34
34
 
35
- HashDeepDiff::Comparison.new(left, right).report
35
+ print HashDeepDiff::Comparison.new(left, right).report
36
36
  ```
37
37
  ```diff
38
38
  - left[a] = a
39
39
  + left[a] = b
40
40
  ```
41
+ ### Arrays
42
+ ```ruby
43
+ left = [1, 2, { a: :a }]
44
+ right = [2, { a: :b }, 3]
45
+
46
+ print HashDeepDiff::Comparison.new(left, right).report
47
+ ```
48
+ ```diff
49
+ -left[...] = [1]
50
+ +left[...] = [3]
51
+ -left[{}][a] = a
52
+ +left[{}][a] = b
53
+ ```
54
+ ### Nesting
55
+ ```ruby
56
+ left = { a: [1, 2, { a: :a } ], b: { c: [1, 2, { d: :e } ] } }
57
+ right = { a: [2, { a: :b }, 3], b: { c: { f: { g: :h } } } }
58
+
59
+ print HashDeepDiff::Comparison.new(left, right).report
60
+ ```
61
+ ```diff
62
+ -left[a][...] = [1]
63
+ +left[a][...] = [3]
64
+ -left[a][{}][a] = a
65
+ +left[a][{}][a] = b
66
+ +left[b][c][...][f] = {}
67
+ +left[b][c][...][f][g] = h
68
+ -left[b][c][...][f] = [1, 2]
69
+ -left[b][c][{}][d] = e
70
+ ```
71
+ ### Reporting Engines
72
+ You can choose from the default diff-like reporting engine (examples are above) and YML reporting engine
73
+
74
+ ```ruby
75
+ left = { a: [1, 2, { a: :a } ], b: { c: [1, 2, { d: :e } ] } }
76
+ right = { a: [2, { a: :b }, 3], b: { c: { f: { g: :h } } } }
77
+ ```
78
+ #### Raw Report
79
+
80
+ ```ruby
81
+ print HashDeepDiff::Comparison.new(left, right, reporting_engine: HashDeepDiff::Reports::Yml).raw_report
82
+ => {"additions"=>{:a=>[3, {:a=>:b}], :b=>{:c=>[{:f=>{:g=>:h}}]}},
83
+ "deletions"=>{:a=>[1, {:a=>:a}], :b=>{:c=>[1, 2, {:d=>:e}]}}}
84
+ ```
85
+
86
+ #### YML Report
87
+
88
+ ```ruby
89
+ print HashDeepDiff::Comparison.new(left, right, reporting_engine: HashDeepDiff::Reports::Yml).report
90
+
91
+ ---
92
+ additions:
93
+ :a:
94
+ - 3
95
+ - :a: :b
96
+ :b:
97
+ :c:
98
+ - :f:
99
+ :g: :h
100
+ deletions:
101
+ :a:
102
+ - 1
103
+ - :a: :a
104
+ :b:
105
+ :c:
106
+ - 1
107
+ - 2
108
+ - :d: :e
109
+ ```
110
+
41
111
  please see [Documentation](https://rdoc.info/gems/hash_deep_diff/HashDeepDiff/Comparison) for
42
112
  more information or [Reporting test](https://github.com/bpohoriletz/hash_deep_diff/blob/a525d239189b0310aec3741dfc4862834805252d/test/integration/locales/test_uk_ru.rb#L59)
43
113
 
114
+
115
+
44
116
  ## Customization
45
117
 
46
118
  You can implement and use your own reporting engines with the default `HashDeepDiff::Delta` objects as a source of the report. In order to do so implement your own version of the reporting engine (example can be found [here](https://github.com/bpohoriletz/hash_deep_diff/tree/main/lib/hash_deep_diff/reports)) and inject it into a `Comparison`
@@ -53,5 +53,7 @@ Gem::Specification.new do |spec|
53
53
  spec.add_development_dependency 'rake', '~> 10.5.0'
54
54
  spec.add_development_dependency 'rubocop', '~> 1.26.1'
55
55
  spec.add_development_dependency 'rubocop-minitest', '~> 0.18.0'
56
+ spec.add_development_dependency 'rubocop-performance', '~> 1.13.3'
56
57
  spec.add_development_dependency 'rubocop-rake', '~> 0.6.0'
58
+ spec.add_development_dependency 'rubocop-rspec', '~> 2.10.0'
57
59
  end
@@ -0,0 +1,116 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+
5
+ module HashDeepDiff
6
+ # Key for a compared value inside Array or Hash
7
+ class ChangeKey
8
+ extend Forwardable
9
+ def_delegators :to_ary, :[], :+, :map, :==, :first, :shift, :empty?
10
+ # element that indicates nested Hash
11
+ NESTED_HASH = '{}'
12
+ # element that indicates Array value
13
+ ARRAY_VALUE = '...'
14
+
15
+ # based on the first element of the key returns the initial object
16
+ # to buld the change representation
17
+ # @return [Array, Hash]
18
+ def self.initial_object(values:)
19
+ return [] if values.size.positive? && [NESTED_HASH, ARRAY_VALUE].include?(values[0][0][0])
20
+
21
+ {}
22
+ end
23
+
24
+ # set the value inside Hash based on the change_key
25
+ # @return [Array, Hash]
26
+ # TOFIX; check if @path are mutated
27
+ def set(obj, value, clone_keys = path.clone)
28
+ # 1. Fetch key
29
+ current_key = clone_keys.shift
30
+ # 2. Prepare object for further processing
31
+ init_value(current_key, obj, clone_keys)
32
+ init_nesting(current_key, obj, clone_keys)
33
+ # 3. Set value - directly or recursively
34
+ set_value(current_key, obj, value, clone_keys)
35
+ recursive_set(current_key, obj, value, clone_keys)
36
+
37
+ return obj
38
+ end
39
+
40
+ # see {#to_ary}
41
+ # @return [Array]
42
+ def to_a
43
+ to_ary
44
+ end
45
+
46
+ # array with keysused to initialize the object
47
+ # @return [Array]
48
+ def to_ary
49
+ path
50
+ end
51
+
52
+ # see {#to_str}
53
+ # @return [String]
54
+ def to_s
55
+ to_str
56
+ end
57
+
58
+ # visual representation of the change key
59
+ # @return [String]
60
+ def to_str
61
+ path.map { |key| "[#{key}]" }.join
62
+ end
63
+
64
+ private
65
+
66
+ attr_reader :path
67
+
68
+ def initialize(path:)
69
+ @path = path.to_ary
70
+ end
71
+
72
+ # prepare an object before further processing
73
+ def init_value(current_key, obj, clone_keys)
74
+ if [ARRAY_VALUE] == clone_keys || NESTED_HASH == clone_keys.first
75
+ obj[current_key] ||= []
76
+ elsif !clone_keys.empty? && ![ARRAY_VALUE, NESTED_HASH].include?(current_key)
77
+ obj[current_key] ||= {}
78
+ end
79
+ end
80
+
81
+ # prepare nesting before further processing
82
+ def init_nesting(current_key, obj, clone_keys)
83
+ element = if NESTED_HASH == current_key
84
+ obj
85
+ elsif NESTED_HASH == clone_keys.first
86
+ obj[current_key]
87
+ end
88
+ element << {} unless element.nil? || element.last.respond_to?(:to_hash)
89
+ end
90
+
91
+ # no more nesting - set value inside object
92
+ def set_value(current_key, obj, value, clone_keys)
93
+ if ARRAY_VALUE == current_key
94
+ obj.prepend(*value)
95
+ clone_keys.pop
96
+ elsif clone_keys.empty?
97
+ obj[current_key] = value
98
+ clone_keys.pop
99
+ elsif [ARRAY_VALUE] == clone_keys
100
+ obj[current_key] = value + obj[current_key]
101
+ clone_keys.pop
102
+ end
103
+ end
104
+
105
+ # recursion for deeply nested values
106
+ def recursive_set(current_key, obj, value, clone_keys)
107
+ if NESTED_HASH == current_key
108
+ set(obj.last, value, clone_keys)
109
+ elsif NESTED_HASH == clone_keys.first
110
+ set(obj[current_key].last, value, clone_keys[1..])
111
+ elsif !clone_keys.empty?
112
+ set(obj[current_key], value, clone_keys)
113
+ end
114
+ end
115
+ end
116
+ end
@@ -21,36 +21,22 @@ module HashDeepDiff
21
21
  # NO_VALUE compared to { one: { three: :c } } compared - value was added
22
22
  # i.e NO_VALUE vas replaced with :c on path [:one, :three]
23
23
  # [
24
- # #<HashDeepDiff::Delta
25
- # @delta={:two=>{:left=>:a, :right=>:b}},
26
- # @prefix=[:one],
24
+ # #<HashDeepDiff::Delta:0x00007fc7bc8a6e58
25
+ # @change_key=#<HashDeepDiff::ChangeKey:0x00007fc7bc8a6d40 @path=[:one, :two]>,
27
26
  # @value={:left=>:a, :right=>:b}>,
28
- # #<HashDeepDiff::Delta
29
- # @delta={:zero=>{:left=>:z, :right=>HashDeepDiff::NO_VALUE}},
30
- # @prefix=[:one],
27
+ # #<HashDeepDiff::Delta:0x00007fc7bc8a6b60
28
+ # @change_key=#<HashDeepDiff::ChangeKey:0x00007fc7bc8a6a48 @path=[:one, :zero]>,
31
29
  # @value={:left=>:z, :right=>HashDeepDiff::NO_VALUE}>,
32
- # #<HashDeepDiff::Delta
33
- # @delta={:three=>{:left=>HashDeepDiff::NO_VALUE, :right=>:c}},
34
- # @prefix=[:one],
35
- # @value={:left=>HashDeepDiff::NO_VALUE, :right=>:c}>
30
+ # #<HashDeepDiff::Delta:0x00007fc7bc8a6930
31
+ # @change_key=#<HashDeepDiff::ChangeKey:0x00007fc7bc8a6818 @path=[:one, :three]>,
32
+ # @value={:left=>HashDeepDiff::NO_VALUE, :right=>:c}>]
36
33
  # ]
37
34
  class Comparison
38
35
  extend Forwardable
39
- # @!attribute [r] left
40
- # @return [Hash] original version of the Hash
41
- # @!attribute [r] right
42
- # @return [Hash] Hash that the original is compared to
43
- # @!attribute [r] path
44
- # @return [Array<Object>] subset of keys from original Hashes to fetch compared values
45
- # (is empty for top-level comparison)
46
36
  attr_reader :reporting_engine, :delta_engine
47
37
 
48
38
  def_delegators :comparison_factory, :comparison
49
-
50
- # @return [String]
51
- def report
52
- diff.map { |simple_delta| reporting_engine.new(delta: simple_delta).to_s }.join
53
- end
39
+ def_delegators :report_engine_factory, :report, :raw_report
54
40
 
55
41
  # @return [Array<HashDeepDiff::Delta>]
56
42
  def diff
@@ -79,6 +65,9 @@ module HashDeepDiff
79
65
 
80
66
  private
81
67
 
68
+ # @!attribute [r] path
69
+ # @return [Array<Object>] subset of keys from original Hashes to fetch compared values
70
+ # (is empty for top-level comparison)
82
71
  attr_reader :path
83
72
 
84
73
  # @param [Object] original original version
@@ -132,18 +121,23 @@ module HashDeepDiff
132
121
  keys.uniq
133
122
  end
134
123
 
124
+ # factory function
125
+ # @return [HashDeepDiff::Delta]
126
+ def delta(key: NO_VALUE)
127
+ keys = path
128
+ keys += [key] unless key == NO_VALUE
129
+
130
+ HashDeepDiff::Delta.new(path: keys, value: { left: left(key), right: right(key) })
131
+ end
132
+
135
133
  # @return [HashDeepDiff::Factories::Comparison]
136
134
  def comparison_factory
137
135
  HashDeepDiff::Factories::Comparison.new(reporting_engine: reporting_engine)
138
136
  end
139
137
 
140
- # factory function
141
- # @return [HashDeepDiff::Delta]
142
- def delta(key: NO_VALUE)
143
- change_key = path
144
- change_key += [key] unless key == NO_VALUE
145
-
146
- HashDeepDiff::Delta.new(change_key: change_key, value: { left: left(key), right: right(key) })
138
+ # @return [HashDeepDiff::Reports::Base]
139
+ def report_engine_factory
140
+ reporting_engine.new(diff: diff)
147
141
  end
148
142
  end
149
143
  end
@@ -20,7 +20,7 @@ module HashDeepDiff
20
20
  def placebo
21
21
  placebo = simple_left? ? { left: NO_VALUE, right: placebo_elment } : { left: placebo_elment, right: NO_VALUE }
22
22
 
23
- [self.class.new(change_key: change_key, value: placebo)]
23
+ [self.class.new(path: change_key, value: placebo)]
24
24
  end
25
25
 
26
26
  # true if any value is an +Array+ with hashes
@@ -59,11 +59,25 @@ module HashDeepDiff
59
59
  simple_left? && simple_right?
60
60
  end
61
61
 
62
+ # removed element(s)
63
+ def deletion
64
+ return left unless array_with_array?
65
+
66
+ return left - right
67
+ end
68
+
62
69
  # Original value
63
70
  def left
64
71
  value[:left]
65
72
  end
66
73
 
74
+ # added element(s)
75
+ def addition
76
+ return right unless array_with_array?
77
+
78
+ return right - left
79
+ end
80
+
67
81
  # Value we compare to
68
82
  def right
69
83
  value[:right]
@@ -84,12 +98,12 @@ module HashDeepDiff
84
98
 
85
99
  attr_reader :value
86
100
 
87
- # @param [Array] change_key list of keys to fetch values we're comparing
101
+ # @param [Array] path list of keys to fetch values we're comparing
88
102
  # @param [Hash<(:left, :right), Object>] value +Hash+ object with two keys - :left and :right,
89
103
  # that represents compared original value (at :left) and value we compare to (at :right)
90
- def initialize(change_key:, value:)
104
+ def initialize(path:, value:)
91
105
  @value = value
92
- @change_key = change_key
106
+ @change_key = HashDeepDiff::ChangeKey.new(path: path)
93
107
  end
94
108
 
95
109
  # an indication of added/removed nested Hash
@@ -111,5 +125,11 @@ module HashDeepDiff
111
125
  def simple_right?
112
126
  !right.respond_to?(:to_hash) && !complex_right?
113
127
  end
128
+
129
+ # true if both left and right are arrays
130
+ # @return [TrueClass, FalseClass]
131
+ def array_with_array?
132
+ left.respond_to?(:to_ary) && right.respond_to?(:to_ary)
133
+ end
114
134
  end
115
135
  end
@@ -42,8 +42,8 @@ module HashDeepDiff
42
42
  when :change
43
43
  return [[value_left, value_right, change_key]] unless complex?
44
44
 
45
- [[value_left, value_right, change_key + ['...']],
46
- [nesting_left, nesting_right, change_key + ['{}']]]
45
+ [[value_left, value_right, change_key + [ChangeKey::ARRAY_VALUE]],
46
+ [nesting_left, nesting_right, change_key + [ChangeKey::NESTED_HASH]]]
47
47
  when :deletion
48
48
  [[value_left, NO_VALUE, change_key]]
49
49
  when :addition
@@ -54,6 +54,7 @@ module HashDeepDiff
54
54
  # original value without nested hashes
55
55
  # @return [Object]
56
56
  def value_left
57
+ return NO_VALUE if left.respond_to?(:to_hash) && right.respond_to?(:to_ary)
57
58
  return left unless left.respond_to?(:to_ary)
58
59
 
59
60
  left.reject { |el| el.respond_to?(:to_hash) }
@@ -62,6 +63,7 @@ module HashDeepDiff
62
63
  # changed value without nested hashes
63
64
  # @return [Object]
64
65
  def value_right
66
+ return NO_VALUE if right.respond_to?(:to_hash) && left.respond_to?(:to_ary)
65
67
  return right unless right.respond_to?(:to_ary)
66
68
 
67
69
  right.reject { |el| el.respond_to?(:to_hash) }
@@ -70,6 +72,7 @@ module HashDeepDiff
70
72
  # nested hashes from original value
71
73
  # @return [Array<Hash>]
72
74
  def nesting_left
75
+ return left if left.respond_to?(:to_hash)
73
76
  return NO_VALUE unless complex_left?
74
77
 
75
78
  left
@@ -80,6 +83,7 @@ module HashDeepDiff
80
83
  # nested hashes from changed value
81
84
  # @return [Array<Hash>]
82
85
  def nesting_right
86
+ return right if right.respond_to?(:to_hash)
83
87
  return NO_VALUE unless complex_right?
84
88
 
85
89
  right
@@ -5,44 +5,39 @@ module HashDeepDiff
5
5
  module Reports
6
6
  # Abstract Class
7
7
  class Base
8
+ # raw data for {#report}
9
+ def raw_report
10
+ raise AbstractMethodError
11
+ end
12
+
8
13
  # see {#to_str}
9
14
  # @return [String]
10
15
  def to_s
11
16
  to_str
12
17
  end
13
18
 
14
- # A report on additions and deletions
19
+ # see {#report}
15
20
  # @return [String]
16
21
  def to_str
17
- original + replacement
22
+ report
18
23
  end
19
24
 
20
- private
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)
29
- attr_reader :old_val, :new_val, :change_key
30
-
31
- # @param [Delta] delta diff to report
32
- def initialize(delta:)
33
- @change_key = delta.change_key.to_ary
34
- @old_val = delta.left
35
- @new_val = delta.right
36
- end
37
-
38
- # old value
39
- def original
25
+ # A report on additions and deletions
26
+ # @return [String]
27
+ def report
40
28
  raise AbstractMethodError
41
29
  end
42
30
 
43
- # new value
44
- def replacement
45
- raise AbstractMethodError
31
+ private
32
+
33
+ # @!attribute [r] diff
34
+ # @return [Array<HashDeepDiff::Delta>] set of deltas from Comparison of two objects
35
+ attr_reader :diff
36
+
37
+ # @param [Array<HashDeepDiff::Delta>] diff comparison data to report
38
+ def initialize(diff:, change_key_engine: HashDeepDiff::ChangeKey)
39
+ @diff = diff.to_ary
40
+ @change_key = change_key_engine
46
41
  end
47
42
  end
48
43
  end
@@ -7,50 +7,57 @@ module HashDeepDiff
7
7
  module Reports
8
8
  # Visual representation of the {Delta} as diff
9
9
  class Diff < Base
10
+ # additiond and deletions represented as diff
11
+ # @return [String]
12
+ def report
13
+ raw_report.map { |delta| original(delta) + replacement(delta) }.join
14
+ end
15
+
16
+ # additiond and deletions raw
17
+ # @return [Array<HashDeepDiff::Delta>]
18
+ def raw_report
19
+ diff
20
+ end
21
+
10
22
  private
11
23
 
12
24
  # line of the report with deleted value
13
25
  # @return [String]
14
- def original
15
- return '' if old_val == NO_VALUE
16
- return "#{deletion}#{path} = #{old_val}\n" unless array_to_array?
17
- return '' if array_deletion.empty?
26
+ def original(delta)
27
+ return '' if delta.left == NO_VALUE
28
+ return "#{deletion}#{delta.change_key} = #{delta.left}\n" unless array_to_array?(delta)
29
+ return '' if array_deletion(delta).empty?
18
30
 
19
- "#{deletion}#{path} = #{array_deletion}\n"
31
+ "#{deletion}#{delta.change_key} = #{array_deletion(delta)}\n"
20
32
  end
21
33
 
22
34
  # line of the report with added value
23
35
  # @return [String]
24
- def replacement
25
- return '' if new_val == NO_VALUE
26
- return "#{addition}#{path} = #{new_val}\n" unless array_to_array?
27
- return '' if array_addition.empty?
36
+ def replacement(delta)
37
+ return '' if delta.right == NO_VALUE
38
+ return "#{addition}#{delta.change_key} = #{delta.right}\n" unless array_to_array?(delta)
39
+ return '' if array_addition(delta).empty?
28
40
 
29
- "#{addition}#{path} = #{array_addition}\n"
41
+ "#{addition}#{delta.change_key} = #{array_addition(delta)}\n"
30
42
  end
31
43
 
32
44
  # returns true if original value and replacement are instances of +Array+
33
45
  # @return Bool
34
- def array_to_array?
35
- old_val.instance_of?(Array) && new_val.instance_of?(Array)
46
+ # TOFIX drop
47
+ def array_to_array?(delta)
48
+ delta.left.instance_of?(Array) && delta.right.instance_of?(Array)
36
49
  end
37
50
 
38
51
  # added elemnts of array
39
52
  # @return [Array]
40
- def array_addition
41
- new_val - old_val
53
+ def array_addition(delta)
54
+ delta.right - delta.left
42
55
  end
43
56
 
44
57
  # added elemnts of array
45
58
  # @return [Array]
46
- def array_deletion
47
- old_val - new_val
48
- end
49
-
50
- # Visual representation of keys from compared objects needed to fetch the compared values
51
- # @return [String]
52
- def path
53
- change_key.map { |key| "[#{key}]" }.join
59
+ def array_deletion(delta)
60
+ delta.left - delta.right
54
61
  end
55
62
 
56
63
  # visual indication of addition
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+ require 'forwardable'
5
+ require 'yaml'
6
+
7
+ module HashDeepDiff
8
+ # Different reporting enjines for {Delta}
9
+ module Reports
10
+ # Visual representation of the {Delta} as diff
11
+ class Yml < Base
12
+ extend Forwardable
13
+ def_delegators :@change_key, :initial_object, :dig_set
14
+
15
+ # additions and deletions represented as YAML
16
+ # @return [String]
17
+ def report
18
+ YAML.dump(raw_report)
19
+ end
20
+
21
+ # additions and deletiond represented as Hash
22
+ # @return [Hash]
23
+ def raw_report
24
+ @raw = { 'additions' => initial_object(values: additions), 'deletions' => initial_object(values: deletions) }
25
+
26
+ additions.each { |(change_key, addition)| change_key.set(raw['additions'], addition) }
27
+ deletions.each { |(change_key, deletion)| change_key.set(raw['deletions'], deletion) }
28
+
29
+ return raw
30
+ end
31
+
32
+ private
33
+
34
+ attr_reader :raw
35
+
36
+ # added values
37
+ # @return [Array<HashDeepDiff::Delta>]
38
+ def additions
39
+ diff.reject { |delta| delta.right == NO_VALUE }
40
+ .map { |delta| [delta.change_key, delta.addition] }
41
+ .reject { |(_, addition)| [] == addition }
42
+ end
43
+
44
+ # deleted values
45
+ # @return [Array<HashDeepDiff::Delta>]
46
+ def deletions
47
+ diff.reject { |delta| delta.left == NO_VALUE }
48
+ .map { |delta| [delta.change_key, delta.deletion] }
49
+ .reject { |(_, deletion)| [] == deletion }
50
+ end
51
+ end
52
+ end
53
+ end
@@ -2,5 +2,5 @@
2
2
 
3
3
  module HashDeepDiff
4
4
  # Version of a gem
5
- VERSION = '0.7.0'
5
+ VERSION = '0.8.0'
6
6
  end
@@ -2,7 +2,9 @@
2
2
 
3
3
  require 'hash_deep_diff/version'
4
4
  require 'hash_deep_diff/reports/diff'
5
+ require 'hash_deep_diff/reports/yml'
5
6
  require 'hash_deep_diff/delta'
7
+ require 'hash_deep_diff/change_key'
6
8
  require 'hash_deep_diff/comparison'
7
9
 
8
10
  # Global namespace
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.7.0
4
+ version: 0.8.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-05-05 00:00:00.000000000 Z
11
+ date: 2022-05-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -192,6 +192,20 @@ dependencies:
192
192
  - - "~>"
193
193
  - !ruby/object:Gem::Version
194
194
  version: 0.18.0
195
+ - !ruby/object:Gem::Dependency
196
+ name: rubocop-performance
197
+ requirement: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - "~>"
200
+ - !ruby/object:Gem::Version
201
+ version: 1.13.3
202
+ type: :development
203
+ prerelease: false
204
+ version_requirements: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - "~>"
207
+ - !ruby/object:Gem::Version
208
+ version: 1.13.3
195
209
  - !ruby/object:Gem::Dependency
196
210
  name: rubocop-rake
197
211
  requirement: !ruby/object:Gem::Requirement
@@ -206,6 +220,20 @@ dependencies:
206
220
  - - "~>"
207
221
  - !ruby/object:Gem::Version
208
222
  version: 0.6.0
223
+ - !ruby/object:Gem::Dependency
224
+ name: rubocop-rspec
225
+ requirement: !ruby/object:Gem::Requirement
226
+ requirements:
227
+ - - "~>"
228
+ - !ruby/object:Gem::Version
229
+ version: 2.10.0
230
+ type: :development
231
+ prerelease: false
232
+ version_requirements: !ruby/object:Gem::Requirement
233
+ requirements:
234
+ - - "~>"
235
+ - !ruby/object:Gem::Version
236
+ version: 2.10.0
209
237
  description: Find the exact difference between two Hash objects
210
238
  email:
211
239
  - bohdan.pohorilets@gmail.com
@@ -237,11 +265,13 @@ files:
237
265
  - bin/yri
238
266
  - hash_deep_diff.gemspec
239
267
  - lib/hash_deep_diff.rb
268
+ - lib/hash_deep_diff/change_key.rb
240
269
  - lib/hash_deep_diff/comparison.rb
241
270
  - lib/hash_deep_diff/delta.rb
242
271
  - lib/hash_deep_diff/factories/comparison.rb
243
272
  - lib/hash_deep_diff/reports/base.rb
244
273
  - lib/hash_deep_diff/reports/diff.rb
274
+ - lib/hash_deep_diff/reports/yml.rb
245
275
  - lib/hash_deep_diff/version.rb
246
276
  homepage: https://github.com/bpohoriletz/hash_deep_diff
247
277
  licenses: