hash_deep_diff 0.5.0 → 0.6.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: 3aab07a4c397dbc84845d5f0faff052bbae89eb8be4bf24a5ed9df0d5129c3da
4
- data.tar.gz: 2ea89b301d808655625e0fa6a9c5028b9d194bba3c4dc54cf1f5c6859c59fc6f
3
+ metadata.gz: ddbaa8e8f12ba99330973c609c00ab710e9fa39b369797b80dd46f24aa6740e1
4
+ data.tar.gz: 6a5954a960ca0876cdb9e28f3e535be687de5596ed07be61581102b75b178ab4
5
5
  SHA512:
6
- metadata.gz: f0a05ee023dbbd4d8551b5065a57a65b645ca3b0a864eace0de91b10ec08da77b0a15df6422af0f5ce0afd4459ca141e227398f9560198f6d350963fac1a99f0
7
- data.tar.gz: 279185ca8464992a65f2fff626b6ee90f44ac7b7e98706e34443390ad24457961b642e5b2ebee10c4c8e3e5c72b7bfee454dd644f8f7ef68db5872c426137dc7
6
+ metadata.gz: af66a50e5a7eb848c96b757e8e37a4d767868de6fd96ebfd4f528085111e2fe1c9e39215b8514d534d33f94cfc4c024c5c2bba1813acad729fa906e18eee796a
7
+ data.tar.gz: 358e25298ee3c42ea469e44113fe62935ec8f564c4111c52e170bd25764d99cc4b71c42d154689ad2a9c54ff21f9359dad57cfbd450677853eb60655b90aecf4
data/Guardfile CHANGED
@@ -25,8 +25,8 @@ end
25
25
  guard :minitest do
26
26
  # with Minitest::Unit
27
27
  watch(%r{^test/(.*)/?test_(.*)\.rb$})
28
- # watch(%r{^lib/(.*/)?([^/]+)\.rb$}) { |m| "test/#{m[1]}test_#{m[2]}.rb" }
29
- watch(%r{^lib/(.*/)?([^/]+)\.rb$}) { 'test' }
28
+ watch(%r{^lib/hash_deep_diff/(.*/)?([^/]+)\.rb$}) { |m| "test/unit/#{m[1]}test_#{m[2]}.rb" }
29
+ # watch(%r{^lib/(.*/)?([^/]+)\.rb$}) { 'test' }
30
30
  watch(%r{^test/test_helper\.rb$}) { 'test' }
31
31
  watch(%r{^test/support/.*$}) { 'test' }
32
32
  end
data/README.md CHANGED
@@ -36,8 +36,19 @@ HashDeepDiff::Comparison.new(left, right).report
36
36
  - left[a] = a
37
37
  + left[a] = b
38
38
  ```
39
- please see [Documentation](https://rdoc.info/gems/hash_deep_diff) for
40
- more info
39
+ please see [Documentation](https://rdoc.info/gems/hash_deep_diff/HashDeepDiff/Comparison) for
40
+ more information
41
+
42
+ ## Customization
43
+
44
+ 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`
45
+
46
+ ```ruby
47
+ left = { a: :a }
48
+ right = { a: :b }
49
+
50
+ HashDeepDiff::Comparison.new(left, right, reporting_engine: CustomEngine).report
51
+ ```
41
52
 
42
53
  ## Contributing
43
54
 
@@ -22,6 +22,7 @@ Gem::Specification.new do |spec|
22
22
  spec.metadata['allowed_push_host'] = 'https://rubygems.org/'
23
23
 
24
24
  spec.metadata['homepage_uri'] = spec.homepage
25
+ spec.metadata['documentation_uri'] = 'https://rdoc.info/gems/hash_deep_diff'
25
26
  spec.metadata['source_code_uri'] = 'https://github.com/bpohoriletz/hash_deep_diff'
26
27
  spec.metadata['changelog_uri'] = 'https://github.com/bpohoriletz/hash_deep_diff/blob/main/CHANGELOG.md'
27
28
  spec.metadata['rubygems_mfa_required'] = 'true'
@@ -47,6 +48,7 @@ Gem::Specification.new do |spec|
47
48
  spec.add_development_dependency 'minitest', '~> 5.15.0'
48
49
  spec.add_development_dependency 'minitest-focus', '~> 1.3.1'
49
50
  spec.add_development_dependency 'minitest-reporters', '~> 1.5.0'
51
+ spec.add_development_dependency 'naught', '~> 1.1.0'
50
52
  spec.add_development_dependency 'rake', '~> 10.5.0'
51
53
  spec.add_development_dependency 'rubocop', '~> 1.26.1'
52
54
  spec.add_development_dependency 'rubocop-minitest', '~> 0.18.0'
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'delta'
3
+ require_relative 'factories/comparison'
4
4
 
5
5
  module HashDeepDiff
6
6
  # Representation of the recursive difference between two hashes
@@ -11,12 +11,12 @@ module HashDeepDiff
11
11
  #
12
12
  # Examples:
13
13
  # - { one: :a } compared with { one: :b } does not have nesting so we compare keys and values
14
- # - { one: { two: :a, zero: z } } compared with { one: { two: :b, three: :c } } has nesting, so is represented as
14
+ # - { one: { two: :a, zero: :z } } compared with { one: { two: :b, three: :c } } has nesting, so is represented as
15
15
  # - { two: :a } compared with { two: :b, three: :c }, as there is no more nesting we compare keys and values
16
16
  # and have the following comparisons
17
17
  # { one: { two: :a } } compared to { one: { two: :b } } - value was changed
18
18
  # i.e :a vas replaced with :b on path [:one, :two]
19
- # { one: { zero: z } } compared to NO_VALUE - value was deleted
19
+ # { one: { zero: :z } } compared to NO_VALUE - value was deleted
20
20
  # i.e :z vas replaced with NO_VALUE on path [:one, :zero]
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]
@@ -35,70 +35,116 @@ module HashDeepDiff
35
35
  # @value={:left=>HashDeepDiff::NO_VALUE, :right=>:c}>
36
36
  # ]
37
37
  class Comparison
38
+ extend Forwardable
38
39
  # @!attribute [r] left
39
40
  # @return [Hash] original version of the Hash
40
41
  # @!attribute [r] right
41
42
  # @return [Hash] Hash that the original is compared to
42
43
  # @!attribute [r] path
43
- # @return [Array<Object>] to a compared Hashes (is empty for top-level comparison)
44
- attr_reader :left, :right, :path
44
+ # @return [Array<Object>] subset of keys from original Hashes to fetch compared values
45
+ # (is empty for top-level comparison)
46
+ attr_reader :reporting_engine, :delta_engine
47
+
48
+ def_delegators :comparison_factory, :comparison
45
49
 
46
50
  # @return [String]
47
51
  def report
48
- diff.join("\n")
52
+ diff.map { |simple_delta| reporting_engine.new(delta: simple_delta).to_s }.join
49
53
  end
50
54
 
51
55
  # @return [Array<HashDeepDiff::Delta>]
52
56
  def diff
53
- comparison.flat_map do |delta|
54
- # if there are nested hashes we need to compare them furter
55
- # if no we return difference between values (HashDeepDiff::Delta)
56
- delta.complex? ? self.class.new(delta.left, delta.right, delta.path).diff : delta
57
- end
57
+ return [] if left == right
58
+
59
+ deltas.flat_map { |new_delta| new_delta.simple? ? new_delta : inward_comparison(new_delta) }
60
+ end
61
+
62
+ # @param [Object] key the key which value we're currently comparing
63
+ def left(key = NO_VALUE)
64
+ return NO_VALUE if @left == NO_VALUE
65
+ return @left if key == NO_VALUE
66
+
67
+ @left[key] || NO_VALUE
68
+ end
69
+
70
+ # @param [Object] key the key which value we're currently comparing
71
+ def right(key = NO_VALUE)
72
+ return NO_VALUE if @right == NO_VALUE
73
+ return @right if key == NO_VALUE
74
+
75
+ @right[key] || NO_VALUE
58
76
  end
59
77
 
60
78
  private
61
79
 
62
- # @param [Hash] left original version of the hash
63
- # @param [Hash] right new version of the hash
80
+ attr_reader :path
81
+
82
+ # @param [Object] original original version
83
+ # @param [Object] changed new version
64
84
  # @param [Array] prefix keys to fetch current comparison (not empty for nested comparisons)
65
- def initialize(left, right, prefix = [])
66
- @left = left.to_hash
67
- @right = right.to_hash
85
+ def initialize(original, changed, prefix = [], reporting_engine: Reports::Diff, delta_engine: Delta)
86
+ @left = original
87
+ @right = changed
68
88
  @path = prefix.to_ary
89
+ @reporting_engine = reporting_engine
90
+ @delta_engine = delta_engine
69
91
  end
70
92
 
93
+ # {Comparison} broken down into array of {Delta}
71
94
  # @return [Array<HashDeepDiff::Delta>]
72
- def comparison
95
+ def deltas
96
+ return [delta] if common_keys.empty?
97
+
73
98
  common_keys.each_with_object([]) do |key, memo|
74
99
  next if values_equal?(key)
75
100
 
76
- memo << Delta.new(path: path + [key], value: { left: value_left(key), right: value_right(key) })
101
+ memo << delta(key: key)
102
+ end
103
+ end
104
+
105
+ # depending on circumstances will return necessary comparisons
106
+ # @return [Array<HashDeepDiff::Delta>]
107
+ def inward_comparison(complex_delta)
108
+ 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
115
+ else
116
+ comparison(delta: complex_delta).diff
77
117
  end
78
118
  end
79
119
 
80
120
  # @param [Object] key the key which value we're currently comparing
81
121
  # @return [Bool]
82
122
  def values_equal?(key)
83
- value_right(key).instance_of?(value_left(key).class) && (value_right(key) == value_left(key))
123
+ right(key).instance_of?(left(key).class) && (right(key) == left(key))
84
124
  end
85
125
 
86
- # Original value
87
- # @param [Object] key the key which value we're currently comparing
88
- def value_left(key)
89
- left[key] || NO_VALUE
126
+ # All keys from both original and compared objects
127
+ # @return [Array]
128
+ def common_keys
129
+ keys = []
130
+ keys += left.keys if left.respond_to?(:keys)
131
+ keys += right.keys if right.respond_to?(:keys)
132
+
133
+ keys.uniq
90
134
  end
91
135
 
92
- # Value we compare to
93
- # @param [Object] key the key which value we're currently comparing
94
- def value_right(key)
95
- right[key] || NO_VALUE
136
+ # @return [HashDeepDiff::Factories::Comparison]
137
+ def comparison_factory
138
+ HashDeepDiff::Factories::Comparison.new(reporting_engine: reporting_engine)
96
139
  end
97
140
 
98
- # All keys from both original and compared objects
99
- # @return [Array]
100
- def common_keys
101
- (left.keys + right.keys).uniq
141
+ # factory function
142
+ # @return [HashDeepDiff::Delta]
143
+ def delta(key: NO_VALUE)
144
+ change_key = path
145
+ change_key += [key] unless key == NO_VALUE
146
+
147
+ HashDeepDiff::Delta.new(change_key: change_key, value: { left: left(key), right: right(key) })
102
148
  end
103
149
  end
104
150
  end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'acts_as_hash'
4
- require_relative 'report'
3
+ require 'forwardable'
5
4
 
6
5
  module HashDeepDiff
7
6
  # Representation of the diff of two values
@@ -10,74 +9,83 @@ module HashDeepDiff
10
9
  # - diff of { a: a } and { a: b } is { a: { left: a, right: b } }
11
10
  # - diff of {} and { a: b } is { a: { left: HashDeepDiff::NO_VALUE, right: b } }
12
11
  class Delta
13
- include ActsAsHash
12
+ extend Forwardable
14
13
 
15
- # Visual representation of additions and deletiond at given +path+
16
- # @return [String]
17
- def to_str
18
- [deletion, addition].compact.join("\n")
14
+ def_delegators :to_hash, :==, :each_with_object, :each_key, :[],
15
+ :to_a, :empty?, :keys
16
+ attr_reader :change_key
17
+
18
+ # an indication that nested Hash was deleted/added
19
+ # @return [HashDeepDiff::Delta, NilClass]
20
+ def placebo
21
+ return nil unless partial?
22
+
23
+ placebo = simple_left? ? { left: NO_VALUE, right: {} } : { left: {}, right: NO_VALUE }
24
+
25
+ self.class.new(change_key: change_key, value: placebo)
19
26
  end
20
27
 
21
- # Returns true if we have nested Hashes
28
+ # true if at least one of the values is a Hash
22
29
  # @return [Bool]
23
- def complex?
24
- left.respond_to?(:to_hash) && right.respond_to?(:to_hash)
30
+ def partial?
31
+ !composite? && !simple?
25
32
  end
26
33
 
27
- # Keys needed to fetch values that we're comparing
28
- # @return [Array]
29
- def path
30
- @prefix + [@delta.keys.first]
34
+ # true if both valus are Hashes
35
+ # @return [Bool]
36
+ def composite?
37
+ !simple_left? && !simple_right?
38
+ end
39
+
40
+ # true if none of the values is a Hash
41
+ # @return [Bool]
42
+ def simple?
43
+ simple_left? && simple_right?
31
44
  end
32
45
 
33
46
  # Original value
34
47
  def left
35
- @value[:left]
48
+ value[:left]
36
49
  end
37
50
 
38
51
  # Value we compare to
39
52
  def right
40
- @value[:right]
53
+ value[:right]
41
54
  end
42
55
 
43
- # See {#to_str}
44
- def to_s
45
- to_str
56
+ # see {#to_hash}
57
+ # @return [Hash]
58
+ def to_h
59
+ to_hash
60
+ end
61
+
62
+ # @return [Hash]
63
+ def to_hash
64
+ { change_key[-1] => value }
46
65
  end
47
66
 
48
67
  private
49
68
 
50
- # @param [Array, Object] path list of keys to fetch values we're comparing
69
+ attr_reader :value
70
+
71
+ # @param [Array] change_key list of keys to fetch values we're comparing
51
72
  # @param [Hash<(:left, :right), Object>] value +Hash+ object with two keys - :left and :right,
52
73
  # that represents compared original value (at :left) and value we compare to (at :right)
53
- def initialize(path:, value:)
54
- # TOFIX this may prohibit usage of hashes with Array keys
55
- # TOFIX extract path to a separate object
56
- if path.respond_to?(:to_ary)
57
- @delta = { path[-1] => value }
58
- @value = value
59
- @prefix = path[0..-2]
60
- else
61
- @delta = { path => value }
62
- @value = value
63
- @prefix = []
64
- end
74
+ def initialize(change_key:, value:)
75
+ @value = value
76
+ @change_key = change_key
65
77
  end
66
78
 
67
- # Visual representation of additions
68
- # @return [NillClass, String]
69
- def deletion
70
- return nil if left == NO_VALUE
71
-
72
- Report.new(path: path, value: left, mode: Report::Mode::DELETION)
79
+ # Returns true if left value has no nested Hashes
80
+ # @return [Bool]
81
+ def simple_left?
82
+ !left.respond_to?(:to_hash)
73
83
  end
74
84
 
75
- # Visual representation of deletions
76
- # @return [NillClass, String]
77
- def addition
78
- return nil if right == NO_VALUE
79
-
80
- Report.new(path: path, value: right)
85
+ # Returns true if right value has no nested Hashes
86
+ # @return [Bool]
87
+ def simple_right?
88
+ !right.respond_to?(:to_hash)
81
89
  end
82
90
  end
83
91
  end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+
5
+ module HashDeepDiff
6
+ # factories
7
+ module Factories
8
+ # Factory for {HashDeepDiff::Comparison}
9
+ class Comparison
10
+ extend Forwardable
11
+ def_delegators :delta, :left, :right, :change_key
12
+
13
+ # factory function
14
+ # @return [Comparison]
15
+ def comparison(delta:, modifier: nil)
16
+ @delta = delta
17
+
18
+ case modifier
19
+ when nil
20
+ full_compare
21
+ when :left
22
+ compare_left
23
+ when :right
24
+ compare_right
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ attr_reader :reporting_engine, :delta
31
+
32
+ def initialize(reporting_engine:)
33
+ @reporting_engine = reporting_engine
34
+ end
35
+
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)
41
+ end
42
+
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)
48
+ end
49
+
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)
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HashDeepDiff
4
+ # Different reporting enjines for {Delta}
5
+ module Reports
6
+ # Abstract Class
7
+ class Base
8
+ # see {#to_str}
9
+ # @return [String]
10
+ def to_s
11
+ to_str
12
+ end
13
+
14
+ # A report on additions and deletions
15
+ # @return [String]
16
+ def to_str
17
+ original + replacement
18
+ end
19
+
20
+ private
21
+
22
+ attr_reader :old_val, :new_val, :change_key
23
+
24
+ # @param [Delta] delta diff to report
25
+ def initialize(delta:)
26
+ @change_key = delta.change_key.to_ary
27
+ @old_val = delta.left
28
+ @new_val = delta.right
29
+ end
30
+
31
+ # old value
32
+ def original
33
+ raise AbstractMethodError
34
+ end
35
+
36
+ # new value
37
+ def replacement
38
+ raise AbstractMethodError
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ module HashDeepDiff
6
+ # Different reporting enjines for {Delta}
7
+ module Reports
8
+ # Visual representation of the {Delta} as diff
9
+ class Diff < Base
10
+ private
11
+
12
+ # old value
13
+ # @return [String]
14
+ def original
15
+ return '' if old_val == NO_VALUE
16
+
17
+ return "#{deletion}#{path} = #{old_val}\n"
18
+ end
19
+
20
+ # new value
21
+ # @return [String]
22
+ def replacement
23
+ return '' if new_val == NO_VALUE
24
+
25
+ return "#{addition}#{path} = #{new_val}\n"
26
+ end
27
+
28
+ # Visual representation of keys from compared objects needed to fetch the compared values
29
+ # @return [String]
30
+ def path
31
+ change_key.map { |key| "[#{key}]" }.join
32
+ end
33
+
34
+ # visual indication of addition
35
+ # @return [String]
36
+ def addition
37
+ '+left'
38
+ end
39
+
40
+ # visual indication of deletion
41
+ # @return [String]
42
+ def deletion
43
+ '-left'
44
+ end
45
+ end
46
+ end
47
+ end
@@ -2,5 +2,5 @@
2
2
 
3
3
  module HashDeepDiff
4
4
  # Version of a gem
5
- VERSION = '0.5.0'
5
+ VERSION = '0.6.0'
6
6
  end
@@ -1,10 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'hash_deep_diff/version'
4
+ require 'hash_deep_diff/reports/diff'
5
+ require 'hash_deep_diff/delta'
4
6
  require 'hash_deep_diff/comparison'
5
7
 
6
8
  # Global namespace
7
9
  module HashDeepDiff
8
10
  # value was not found
9
11
  NO_VALUE = Class.new(NilClass)
12
+ # Abstract method
13
+ AbstractMethodError = Class.new(NoMethodError)
14
+ # Any error
15
+ Error = Class.new(StandardError)
10
16
  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.5.0
4
+ version: 0.6.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-18 00:00:00.000000000 Z
11
+ date: 2022-04-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -122,6 +122,20 @@ dependencies:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
124
  version: 1.5.0
125
+ - !ruby/object:Gem::Dependency
126
+ name: naught
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: 1.1.0
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: 1.1.0
125
139
  - !ruby/object:Gem::Dependency
126
140
  name: rake
127
141
  requirement: !ruby/object:Gem::Requirement
@@ -209,10 +223,11 @@ files:
209
223
  - bin/yri
210
224
  - hash_deep_diff.gemspec
211
225
  - lib/hash_deep_diff.rb
212
- - lib/hash_deep_diff/acts_as_hash.rb
213
226
  - lib/hash_deep_diff/comparison.rb
214
227
  - lib/hash_deep_diff/delta.rb
215
- - lib/hash_deep_diff/report.rb
228
+ - lib/hash_deep_diff/factories/comparison.rb
229
+ - lib/hash_deep_diff/reports/base.rb
230
+ - lib/hash_deep_diff/reports/diff.rb
216
231
  - lib/hash_deep_diff/version.rb
217
232
  homepage: https://github.com/bpohoriletz/hash_deep_diff
218
233
  licenses:
@@ -220,6 +235,7 @@ licenses:
220
235
  metadata:
221
236
  allowed_push_host: https://rubygems.org/
222
237
  homepage_uri: https://github.com/bpohoriletz/hash_deep_diff
238
+ documentation_uri: https://rdoc.info/gems/hash_deep_diff
223
239
  source_code_uri: https://github.com/bpohoriletz/hash_deep_diff
224
240
  changelog_uri: https://github.com/bpohoriletz/hash_deep_diff/blob/main/CHANGELOG.md
225
241
  rubygems_mfa_required: 'true'
@@ -1,31 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'forwardable'
4
-
5
- module HashDeepDiff
6
- # This module includes behavior that is needed to use instances of Delta instead of Hash
7
- # in this gem
8
- module ActsAsHash
9
- # @param [Object] base a hook that is invoked when module is included in a class
10
- def self.included(base)
11
- base.extend Forwardable
12
- base.def_delegators :@delta, :==, :each_with_object, :each_key, :[],
13
- :to_a, :empty?, :keys
14
- base.include InstanceMethods
15
- end
16
-
17
- # We assume that the class will initialize instance variable +@delta+ that will return
18
- # a representation of an instance of a class as a +Hash+ object
19
- module InstanceMethods
20
- # a +Hash+ representation of an object
21
- def to_h
22
- to_hash
23
- end
24
-
25
- # a +Hash+ representation of an object
26
- def to_hash
27
- @delta
28
- end
29
- end
30
- end
31
- end
@@ -1,53 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module HashDeepDiff
4
- # Visual representation of the difference between two values
5
- class Report
6
- # We have two cases
7
- # * added - when value on the left is missing
8
- # * deleted - when the value on the right is missing
9
- module Mode
10
- # for additions
11
- ADDITION = '+left'
12
- # for deletions
13
- DELETION = '-left'
14
- end
15
-
16
- # A report with all additions and deletions
17
- # @return [String]
18
- def to_str
19
- if @value.respond_to?(:to_hash) && !@value.empty?
20
- [@mode, diff_prefix, ' = ', "{}\n"].join +
21
- @value.keys.map do |key|
22
- Report.new(path: @path + [key], value: @value[key], mode: @mode)
23
- end.join("\n")
24
- else
25
- [@mode, diff_prefix, ' = ', @value.to_s].join
26
- end
27
- end
28
-
29
- # A report with all additions and deletions
30
- # @return [String]
31
- def to_s
32
- to_str
33
- end
34
-
35
- private
36
-
37
- # @param [Array] path Keys from compared objects to fetch the compared values
38
- # @param [Object] value value from a compared object at +@path+
39
- # @param [Mode::ADDITION, Mode::DELETION] mode
40
- def initialize(path:, value:, mode: Mode::ADDITION)
41
- @path = path.to_ary
42
- @value = value
43
- @mode = mode
44
- end
45
-
46
- # Visual representation of keys from compared objects needed to fetch the compared values
47
- # @return [String]
48
- def diff_prefix
49
- # TOFIX poor naming
50
- @path.map { |key| "[#{key}]" }.join
51
- end
52
- end
53
- end