hash_deep_diff 0.3.3 → 0.4.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: fe3724394c10b36b7537f35bce5c7f079cae0ee3344062a78bdfe7256363624b
4
- data.tar.gz: e9baa112b03013b91f75ebea9f243a0a6d51ca746ca8c8e66ea6fa38803198fd
3
+ metadata.gz: 24756c15f3f48bbe108e5c2bb12c2db3e6030cef78ab91a6cf76044ca70d2dd5
4
+ data.tar.gz: a8cca8ab8a23c704f6f69c2613ded6b4d0d2c7b0e5caed34d437fe0951582a45
5
5
  SHA512:
6
- metadata.gz: b7393bb437eddfb8e0ed66d4eba3b4135e221c7c2262df14aa4509dba98345c4766b598bd3c3f11f311c84b25b4f9f0b2bca3dfc5083c023c87c582fa607761a
7
- data.tar.gz: 57708513050ac1e63c0ce64b9650e0ae0e3128127cbb4dfc5b248cc3caca3267cbd26bed7b939be4413c11f1a7038f5503aef143119a09e336cc113324ae182a
6
+ metadata.gz: 731ccc90f750c6796374ae83ccf9c78741e47251c7940add8f0e9c9c34417f84f8375e74c639891c4e37e5976200bb8786e4bd2dbbe9357bb9b92e8a14b46c7b
7
+ data.tar.gz: 8dfbab0f3e5fd2666e2d5eb3458d9df858e204e49cd604348676af43c511bd855dba61720702cc69c7e3ecd0751e29606eec10bef41ee1a0e8bdd4ba33db79f7
data/CHANGELOG.md ADDED
File without changes
data/README.md CHANGED
@@ -2,6 +2,9 @@
2
2
 
3
3
  Find the exact difference between two Hash objects and build a report to visualize it
4
4
 
5
+ [![Gem
6
+ Version](https://badge.fury.io/rb/hash_deep_diff.svg)](https://badge.fury.io/rb/hash_deep_diff)
7
+
5
8
  ## Installation
6
9
 
7
10
  Add this line to your application's Gemfile:
@@ -29,10 +32,10 @@ HashDeepDiff::Comparison.new(left, right).report
29
32
  ```
30
33
  ```diff
31
34
  - left[a] = a
32
- + right[a] = b
35
+ + left[a] = b
33
36
  ```
34
37
 
35
38
  ## Contributing
36
39
 
37
40
  Bug reports and pull requests are welcome on GitHub at [bpohoriletz](https://github.com/bpohoriletz/hash_deep_diff).
38
-
41
+
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+
5
+ module HashDeepDiff
6
+ # This module includes behavior that is needed to use deltas instead of Hash inside this gem
7
+ module ActsAsHash
8
+ def self.included(base)
9
+ base.include(InstanceMethods)
10
+ base.extend(Forwardable)
11
+ base.def_delegators :@delta, :==, :each_with_object, :each_key, :[],
12
+ :to_a, :empty?, :keys
13
+ end
14
+
15
+ # Assumes that the class will include method delta that will return a representation of an
16
+ # instance of a class as a Hash
17
+ module InstanceMethods
18
+ def to_h
19
+ @delta
20
+ end
21
+
22
+ def to_hash
23
+ @delta
24
+ end
25
+ end
26
+ end
27
+ end
@@ -1,17 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'delta/left'
4
- require_relative 'delta/inner'
5
- require_relative 'delta/right'
3
+ require_relative 'delta'
6
4
 
7
5
  # :nodoc:
8
6
  module HashDeepDiff
9
- # :nodoc:
7
+ # An instrument to build and report the difference between two hash-like objects
10
8
  class Comparison
11
9
  attr_reader :left, :right, :path
12
10
 
13
- def diff(&block)
14
- left_delta + deep_delta(&block) + right_delta
11
+ def diff
12
+ deep_delta
15
13
  end
16
14
 
17
15
  def report
@@ -26,8 +24,8 @@ module HashDeepDiff
26
24
  @path = path.to_ary
27
25
  end
28
26
 
29
- def deep_delta(&block)
30
- delta(&block).flat_map do |diff|
27
+ def deep_delta
28
+ delta.flat_map do |diff|
31
29
  if diff.complex?
32
30
  self.class.new(diff.left, diff.right, diff.path).diff
33
31
  else
@@ -36,37 +34,19 @@ module HashDeepDiff
36
34
  end
37
35
  end
38
36
 
39
- def left_delta
40
- left_diff_keys.map { |key| Delta::Left.new(path: path + [key], value: left[key]) }
41
- end
42
-
43
- def right_delta
44
- right_diff_keys.map { |key| Delta::Right.new(path: path + [key], value: right[key]) }
45
- end
46
-
47
- def delta(&block)
48
- block ||= ->(val) { val }
49
-
37
+ def delta
50
38
  common_keys.each_with_object([]) do |key, memo|
51
- value_left = block.call(left[key])
52
- value_right = block.call(right[key])
39
+ value_left = left[key] || NO_VALUE
40
+ value_right = right[key] || NO_VALUE
53
41
 
54
42
  next if value_right.instance_of?(value_left.class) && (value_right == value_left)
55
43
 
56
- memo << Delta::Inner.new(path: path + [key], value: { left: value_left, right: value_right })
44
+ memo << Delta.new(path: path + [key], value: { left: value_left, right: value_right })
57
45
  end
58
46
  end
59
47
 
60
48
  def common_keys
61
- left.keys & right.keys
62
- end
63
-
64
- def right_diff_keys
65
- right.keys - left.keys
66
- end
67
-
68
- def left_diff_keys
69
- left.keys - right.keys
49
+ (left.keys + right.keys).uniq
70
50
  end
71
51
  end
72
52
  end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'acts_as_hash'
4
+
5
+ module HashDeepDiff
6
+ # Representation of the diff of two values
7
+ # examples:
8
+ # - diff of { a: a } and {} is { a: { left: a, right: HashDeepDiff::NO_VALUE } }
9
+ # - diff of { a: a } and { a: b } is { a: { left: a, right: b } }
10
+ # - diff of {} and { a: b } is { a: { left: HashDeepDiff::NO_VALUE, right: b } }
11
+ class Delta
12
+ include ActsAsHash
13
+
14
+ def to_str
15
+ [deletion, addition].compact.join("\n")
16
+ end
17
+
18
+ def complex?
19
+ left.respond_to?(:to_hash) && right.respond_to?(:to_hash)
20
+ end
21
+
22
+ # TOFIX poor naming
23
+ # overrides parameter in initializer
24
+ def path
25
+ @prefix + [@delta.keys.first]
26
+ end
27
+
28
+ def left
29
+ @value[:left]
30
+ end
31
+
32
+ def right
33
+ @value[:right]
34
+ end
35
+
36
+ def to_s
37
+ to_str
38
+ end
39
+
40
+ private
41
+
42
+ def initialize(path:, value:)
43
+ # TOFIX this may prohibit usage of hashes with Array keys
44
+ if path.respond_to?(:to_ary)
45
+ @delta = { path[-1] => value }
46
+ @value = value
47
+ @prefix = path[0..-2]
48
+ else
49
+ @delta = { path => value }
50
+ @value = value
51
+ @prefix = []
52
+ end
53
+ end
54
+
55
+ def deletion
56
+ return nil if left == NO_VALUE
57
+
58
+ if left.respond_to?(:to_hash)
59
+ left.keys.map { |key| "-left#{diff_prefix}[#{key}] = #{left[key]}" }.join("\n")
60
+ else
61
+ "-left#{diff_prefix} = #{left}"
62
+ end
63
+ end
64
+
65
+ def addition
66
+ return nil if right == NO_VALUE
67
+
68
+ if right.respond_to?(:to_hash)
69
+ right.keys.map { |key| "+left#{diff_prefix}[#{key}] = #{right[key]}" }.join("\n")
70
+ else
71
+ "+left#{diff_prefix} = #{right}"
72
+ end
73
+ end
74
+
75
+ # TOFIX poor naming
76
+ def diff_prefix
77
+ path.map { |key| "[#{key}]" }.join
78
+ end
79
+ end
80
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module HashDeepDiff
4
- VERSION = '0.3.3'
4
+ VERSION = '0.4.0'
5
5
  end
@@ -4,5 +4,6 @@ require 'hash_deep_diff/version'
4
4
  require 'hash_deep_diff/comparison'
5
5
 
6
6
  module HashDeepDiff
7
+ NO_VALUE = Class.new(NilClass)
7
8
  class Error < StandardError; end
8
9
  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.3.3
4
+ version: 0.4.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-13 00:00:00.000000000 Z
11
+ date: 2022-04-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -175,6 +175,7 @@ files:
175
175
  - ".bundle/config"
176
176
  - ".gitignore"
177
177
  - ".rubocop.yml"
178
+ - CHANGELOG.md
178
179
  - Gemfile
179
180
  - Guardfile
180
181
  - README.md
@@ -188,11 +189,9 @@ files:
188
189
  - bin/setup
189
190
  - hash_deep_diff.gemspec
190
191
  - lib/hash_deep_diff.rb
192
+ - lib/hash_deep_diff/acts_as_hash.rb
191
193
  - lib/hash_deep_diff/comparison.rb
192
- - lib/hash_deep_diff/delta/acts_as_delta.rb
193
- - lib/hash_deep_diff/delta/inner.rb
194
- - lib/hash_deep_diff/delta/left.rb
195
- - lib/hash_deep_diff/delta/right.rb
194
+ - lib/hash_deep_diff/delta.rb
196
195
  - lib/hash_deep_diff/version.rb
197
196
  homepage: https://github.com/bpohoriletz/hash_deep_diff
198
197
  licenses:
@@ -1,69 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'forwardable'
4
-
5
- module HashDeepDiff
6
- module Delta
7
- # This module includes behavior that is needed to use deltas instead of Hash inside this gem
8
- module ActsAsDelta
9
- def self.included(base)
10
- base.prepend(Initialize)
11
- base.include(InstanceMethods)
12
- base.extend(Forwardable)
13
- base.def_delegators :@delta, :==, :each_with_object, :each_key, :[],
14
- :to_a, :empty?, :keys
15
- end
16
-
17
- # Assumes that the class will include method delta that will return a representation of an
18
- # instance of a class as a Hash
19
- module InstanceMethods
20
- # TOFIX poor naming
21
- def diff_prefix
22
- path.map { |key| "[#{key}]" }.join
23
- end
24
-
25
- # TOFIX poor naming
26
- # overrides parameter in initializer
27
- def path
28
- @prefix + [@delta.keys.first]
29
- end
30
-
31
- def to_h
32
- @delta
33
- end
34
-
35
- def to_hash
36
- @delta
37
- end
38
-
39
- def to_s
40
- to_str
41
- end
42
-
43
- def to_str
44
- raise NoMethodError, "expected #{self.class} to implement #to_str"
45
- end
46
-
47
- def complex?
48
- raise NoMethodError, "expected #{self.class} to implement #complex?"
49
- end
50
- end
51
-
52
- # Override #initialize method
53
- module Initialize
54
- def initialize(path:, value:)
55
- # TOFIX this may prohibit usage of hashes with Array keys
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
65
- end
66
- end
67
- end
68
- end
69
- end
@@ -1,40 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'acts_as_delta'
4
-
5
- module HashDeepDiff
6
- module Delta
7
- # Representation of the pure left diff
8
- # i.e element that are missing in the hash on the right of the comparison
9
- # for example left diff of { a: a } and {} is { a: a }
10
- class Inner
11
- include Delta::ActsAsDelta
12
-
13
- def to_str
14
- return diff unless complex?
15
-
16
- HashDeepDiff::Comparison.new(left, right, path).report
17
- end
18
-
19
- def diff
20
- lines = <<~Q
21
- -left#{diff_prefix} = #{left}
22
- +right#{diff_prefix} = #{right}
23
- Q
24
- lines.strip
25
- end
26
-
27
- def complex?
28
- left.respond_to?(:to_hash) && right.respond_to?(:to_hash)
29
- end
30
-
31
- def left
32
- @value[:left]
33
- end
34
-
35
- def right
36
- @value[:right]
37
- end
38
- end
39
- end
40
- end
@@ -1,30 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'acts_as_delta'
4
-
5
- module HashDeepDiff
6
- module Delta
7
- # Representation of the pure left diff
8
- # i.e element that are missing in the hash on the right of the comparison
9
- # for example left diff of { a: a } and {} is { a: a }
10
- class Left
11
- include Delta::ActsAsDelta
12
-
13
- def to_str
14
- return "+left#{diff_prefix} = #{left}" unless left.respond_to?(:to_hash)
15
-
16
- left.keys.map do |key|
17
- self.class.new(path: path + [key], value: left[key])
18
- end.join("\n").strip
19
- end
20
-
21
- def left
22
- @value
23
- end
24
-
25
- def right
26
- nil
27
- end
28
- end
29
- end
30
- end
@@ -1,30 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'acts_as_delta'
4
-
5
- module HashDeepDiff
6
- module Delta
7
- # Representation of the pure right diff
8
- # i.e element that are missing in the hash on the right of the comparison
9
- # for example right diff of {} and { a: a } is { a: a }
10
- class Right
11
- include Delta::ActsAsDelta
12
-
13
- def to_str
14
- return "-left#{diff_prefix} = #{right}" unless right.respond_to?(:to_hash)
15
-
16
- right.keys.map do |key|
17
- self.class.new(path: path + [key], value: right[key])
18
- end.join("\n").strip
19
- end
20
-
21
- def left
22
- nil
23
- end
24
-
25
- def right
26
- @value
27
- end
28
- end
29
- end
30
- end