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 +4 -4
- data/Guardfile +2 -2
- data/README.md +13 -2
- data/hash_deep_diff.gemspec +2 -0
- data/lib/hash_deep_diff/comparison.rb +77 -31
- data/lib/hash_deep_diff/delta.rb +52 -44
- data/lib/hash_deep_diff/factories/comparison.rb +58 -0
- data/lib/hash_deep_diff/reports/base.rb +42 -0
- data/lib/hash_deep_diff/reports/diff.rb +47 -0
- data/lib/hash_deep_diff/version.rb +1 -1
- data/lib/hash_deep_diff.rb +6 -0
- metadata +20 -4
- data/lib/hash_deep_diff/acts_as_hash.rb +0 -31
- data/lib/hash_deep_diff/report.rb +0 -53
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ddbaa8e8f12ba99330973c609c00ab710e9fa39b369797b80dd46f24aa6740e1
|
4
|
+
data.tar.gz: 6a5954a960ca0876cdb9e28f3e535be687de5596ed07be61581102b75b178ab4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
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
|
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
|
|
data/hash_deep_diff.gemspec
CHANGED
@@ -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 '
|
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>]
|
44
|
-
|
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.
|
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
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
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
|
-
|
63
|
-
|
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(
|
66
|
-
@left =
|
67
|
-
@right =
|
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
|
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 <<
|
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
|
-
|
123
|
+
right(key).instance_of?(left(key).class) && (right(key) == left(key))
|
84
124
|
end
|
85
125
|
|
86
|
-
#
|
87
|
-
# @
|
88
|
-
def
|
89
|
-
|
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
|
-
#
|
93
|
-
|
94
|
-
|
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
|
-
#
|
99
|
-
# @return [
|
100
|
-
def
|
101
|
-
|
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
|
data/lib/hash_deep_diff/delta.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
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
|
-
|
12
|
+
extend Forwardable
|
14
13
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
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
|
-
#
|
28
|
+
# true if at least one of the values is a Hash
|
22
29
|
# @return [Bool]
|
23
|
-
def
|
24
|
-
|
30
|
+
def partial?
|
31
|
+
!composite? && !simple?
|
25
32
|
end
|
26
33
|
|
27
|
-
#
|
28
|
-
# @return [
|
29
|
-
def
|
30
|
-
|
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
|
-
|
48
|
+
value[:left]
|
36
49
|
end
|
37
50
|
|
38
51
|
# Value we compare to
|
39
52
|
def right
|
40
|
-
|
53
|
+
value[:right]
|
41
54
|
end
|
42
55
|
|
43
|
-
#
|
44
|
-
|
45
|
-
|
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
|
-
|
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(
|
54
|
-
|
55
|
-
|
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
|
-
#
|
68
|
-
# @return [
|
69
|
-
def
|
70
|
-
|
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
|
-
#
|
76
|
-
# @return [
|
77
|
-
def
|
78
|
-
|
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
|
data/lib/hash_deep_diff.rb
CHANGED
@@ -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.
|
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-
|
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/
|
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
|