hash_deep_diff 0.3.3 → 0.5.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: 3aab07a4c397dbc84845d5f0faff052bbae89eb8be4bf24a5ed9df0d5129c3da
4
+ data.tar.gz: 2ea89b301d808655625e0fa6a9c5028b9d194bba3c4dc54cf1f5c6859c59fc6f
5
5
  SHA512:
6
- metadata.gz: b7393bb437eddfb8e0ed66d4eba3b4135e221c7c2262df14aa4509dba98345c4766b598bd3c3f11f311c84b25b4f9f0b2bca3dfc5083c023c87c582fa607761a
7
- data.tar.gz: 57708513050ac1e63c0ce64b9650e0ae0e3128127cbb4dfc5b248cc3caca3267cbd26bed7b939be4413c11f1a7038f5503aef143119a09e336cc113324ae182a
6
+ metadata.gz: f0a05ee023dbbd4d8551b5065a57a65b645ca3b0a864eace0de91b10ec08da77b0a15df6422af0f5ce0afd4459ca141e227398f9560198f6d350963fac1a99f0
7
+ data.tar.gz: 279185ca8464992a65f2fff626b6ee90f44ac7b7e98706e34443390ad24457961b642e5b2ebee10c4c8e3e5c72b7bfee454dd644f8f7ef68db5872c426137dc7
@@ -0,0 +1,39 @@
1
+ name: CI
2
+ on:
3
+ pull_request:
4
+
5
+ jobs:
6
+ minitest:
7
+ runs-on: ubuntu-latest
8
+ steps:
9
+ - name: Checkout Repo
10
+ uses: actions/checkout@v2
11
+
12
+ - name: Install Ruby
13
+ uses: ruby/setup-ruby@v1
14
+ with:
15
+ ruby-version: 2.6
16
+ bundler-cache: false
17
+
18
+ - name: Install Gems
19
+ run: bin/bundle
20
+
21
+ - name: Run Minitest
22
+ run: bin/rake test
23
+ rubocop:
24
+ runs-on: ubuntu-latest
25
+ steps:
26
+ - name: Checkout Repo
27
+ uses: actions/checkout@v2
28
+
29
+ - name: Install Ruby
30
+ uses: ruby/setup-ruby@v1
31
+ with:
32
+ ruby-version: 2.6
33
+ bundler-cache: false
34
+
35
+ - name: Install Gems
36
+ run: bin/bundle
37
+
38
+ - name: Run Rubocop
39
+ run: bin/rubocop
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --private
data/CHANGELOG.md ADDED
File without changes
data/Guardfile CHANGED
@@ -20,7 +20,6 @@
20
20
  guard :rubocop do
21
21
  watch(/.+\.rb$/)
22
22
  watch(/.+\.gemspec$/)
23
- watch(%r{(?:.+/)?\.rubocop(?:_todo)?\.yml$}) { |m| File.dirname(m[0]) }
24
23
  end
25
24
 
26
25
  guard :minitest do
@@ -31,3 +30,7 @@ guard :minitest do
31
30
  watch(%r{^test/test_helper\.rb$}) { 'test' }
32
31
  watch(%r{^test/support/.*$}) { 'test' }
33
32
  end
33
+
34
+ guard 'yard' do
35
+ watch(%r{lib/.+\.rb})
36
+ end
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2021 - 2022 Bohdan Pohorilets
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -1,4 +1,9 @@
1
1
  # HashDeepDiff
2
+ [![Gem
3
+ Version](https://badge.fury.io/rb/hash_deep_diff.svg)](https://badge.fury.io/rb/hash_deep_diff) ![GitHub Workflow
4
+ Status](https://img.shields.io/github/workflow/status/bpohoriletz/hash_deep_diff/CI)
5
+ ![GitHub](https://img.shields.io/github/license/bpohoriletz/hash_deep_diff)
6
+
2
7
 
3
8
  Find the exact difference between two Hash objects and build a report to visualize it
4
9
 
@@ -29,10 +34,12 @@ HashDeepDiff::Comparison.new(left, right).report
29
34
  ```
30
35
  ```diff
31
36
  - left[a] = a
32
- + right[a] = b
37
+ + left[a] = b
33
38
  ```
39
+ please see [Documentation](https://rdoc.info/gems/hash_deep_diff) for
40
+ more info
34
41
 
35
42
  ## Contributing
36
43
 
37
44
  Bug reports and pull requests are welcome on GitHub at [bpohoriletz](https://github.com/bpohoriletz/hash_deep_diff).
38
-
45
+
data/Rakefile CHANGED
@@ -5,7 +5,7 @@ require 'rake/testtask'
5
5
 
6
6
  Rake::TestTask.new do |t|
7
7
  t.libs << 'test'
8
- t.test_files = FileList['test/**/*_spec.rb']
8
+ t.test_files = FileList['test/hash_deep_diff/test_*.rb']
9
9
  t.verbose = true
10
10
  end
11
11
 
data/bin/yard ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'yard' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
12
+
13
+ bundle_binstub = File.expand_path("bundle", __dir__)
14
+
15
+ if File.file?(bundle_binstub)
16
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
17
+ load(bundle_binstub)
18
+ else
19
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
20
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
21
+ end
22
+ end
23
+
24
+ require "rubygems"
25
+ require "bundler/setup"
26
+
27
+ load Gem.bin_path("yard", "yard")
data/bin/yardoc ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'yardoc' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
12
+
13
+ bundle_binstub = File.expand_path("bundle", __dir__)
14
+
15
+ if File.file?(bundle_binstub)
16
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
17
+ load(bundle_binstub)
18
+ else
19
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
20
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
21
+ end
22
+ end
23
+
24
+ require "rubygems"
25
+ require "bundler/setup"
26
+
27
+ load Gem.bin_path("yard", "yardoc")
data/bin/yri ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'yri' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
12
+
13
+ bundle_binstub = File.expand_path("bundle", __dir__)
14
+
15
+ if File.file?(bundle_binstub)
16
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
17
+ load(bundle_binstub)
18
+ else
19
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
20
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
21
+ end
22
+ end
23
+
24
+ require "rubygems"
25
+ require "bundler/setup"
26
+
27
+ load Gem.bin_path("yard", "yri")
@@ -39,10 +39,11 @@ Gem::Specification.new do |spec|
39
39
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
40
40
  spec.require_paths = ['lib']
41
41
 
42
- spec.add_development_dependency 'bundler', '~> 1.17.2'
42
+ spec.add_development_dependency 'bundler', '~> 2.3.11'
43
43
  spec.add_development_dependency 'guard', '~> 2.18.0'
44
44
  spec.add_development_dependency 'guard-minitest', '~> 2.4.6'
45
45
  spec.add_development_dependency 'guard-rubocop', '~> 1.5.0'
46
+ spec.add_development_dependency 'guard-yard', '~> 2.2.1'
46
47
  spec.add_development_dependency 'minitest', '~> 5.15.0'
47
48
  spec.add_development_dependency 'minitest-focus', '~> 1.3.1'
48
49
  spec.add_development_dependency 'minitest-reporters', '~> 1.5.0'
@@ -0,0 +1,31 @@
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,72 +1,104 @@
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
- # :nodoc:
8
5
  module HashDeepDiff
9
- # :nodoc:
6
+ # Representation of the recursive difference between two hashes
7
+ # main parts are
8
+ # * path - empty for original hashes, otherwise path to values being compared
9
+ # * left - basically left.dig(path), left value of two being compared
10
+ # * right - basically right.dig(path), right value of two being compared
11
+ #
12
+ # Examples:
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
15
+ # - { two: :a } compared with { two: :b, three: :c }, as there is no more nesting we compare keys and values
16
+ # and have the following comparisons
17
+ # { one: { two: :a } } compared to { one: { two: :b } } - value was changed
18
+ # i.e :a vas replaced with :b on path [:one, :two]
19
+ # { one: { zero: z } } compared to NO_VALUE - value was deleted
20
+ # i.e :z vas replaced with NO_VALUE on path [:one, :zero]
21
+ # NO_VALUE compared to { one: { three: :c } } compared - value was added
22
+ # i.e NO_VALUE vas replaced with :c on path [:one, :three]
23
+ # [
24
+ # #<HashDeepDiff::Delta
25
+ # @delta={:two=>{:left=>:a, :right=>:b}},
26
+ # @prefix=[:one],
27
+ # @value={:left=>:a, :right=>:b}>,
28
+ # #<HashDeepDiff::Delta
29
+ # @delta={:zero=>{:left=>:z, :right=>HashDeepDiff::NO_VALUE}},
30
+ # @prefix=[:one],
31
+ # @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}>
36
+ # ]
10
37
  class Comparison
38
+ # @!attribute [r] left
39
+ # @return [Hash] original version of the Hash
40
+ # @!attribute [r] right
41
+ # @return [Hash] Hash that the original is compared to
42
+ # @!attribute [r] path
43
+ # @return [Array<Object>] to a compared Hashes (is empty for top-level comparison)
11
44
  attr_reader :left, :right, :path
12
45
 
13
- def diff(&block)
14
- left_delta + deep_delta(&block) + right_delta
15
- end
16
-
46
+ # @return [String]
17
47
  def report
18
48
  diff.join("\n")
19
49
  end
20
50
 
51
+ # @return [Array<HashDeepDiff::Delta>]
52
+ 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
58
+ end
59
+
21
60
  private
22
61
 
23
- def initialize(left, right, path = [])
62
+ # @param [Hash] left original version of the hash
63
+ # @param [Hash] right new version of the hash
64
+ # @param [Array] prefix keys to fetch current comparison (not empty for nested comparisons)
65
+ def initialize(left, right, prefix = [])
24
66
  @left = left.to_hash
25
67
  @right = right.to_hash
26
- @path = path.to_ary
68
+ @path = prefix.to_ary
27
69
  end
28
70
 
29
- def deep_delta(&block)
30
- delta(&block).flat_map do |diff|
31
- if diff.complex?
32
- self.class.new(diff.left, diff.right, diff.path).diff
33
- else
34
- diff
35
- end
71
+ # @return [Array<HashDeepDiff::Delta>]
72
+ def comparison
73
+ common_keys.each_with_object([]) do |key, memo|
74
+ next if values_equal?(key)
75
+
76
+ memo << Delta.new(path: path + [key], value: { left: value_left(key), right: value_right(key) })
36
77
  end
37
78
  end
38
79
 
39
- def left_delta
40
- left_diff_keys.map { |key| Delta::Left.new(path: path + [key], value: left[key]) }
80
+ # @param [Object] key the key which value we're currently comparing
81
+ # @return [Bool]
82
+ def values_equal?(key)
83
+ value_right(key).instance_of?(value_left(key).class) && (value_right(key) == value_left(key))
41
84
  end
42
85
 
43
- def right_delta
44
- right_diff_keys.map { |key| Delta::Right.new(path: path + [key], value: right[key]) }
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
45
90
  end
46
91
 
47
- def delta(&block)
48
- block ||= ->(val) { val }
49
-
50
- common_keys.each_with_object([]) do |key, memo|
51
- value_left = block.call(left[key])
52
- value_right = block.call(right[key])
53
-
54
- next if value_right.instance_of?(value_left.class) && (value_right == value_left)
55
-
56
- memo << Delta::Inner.new(path: path + [key], value: { left: value_left, right: value_right })
57
- end
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
58
96
  end
59
97
 
98
+ # All keys from both original and compared objects
99
+ # @return [Array]
60
100
  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
101
+ (left.keys + right.keys).uniq
70
102
  end
71
103
  end
72
104
  end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'acts_as_hash'
4
+ require_relative 'report'
5
+
6
+ module HashDeepDiff
7
+ # Representation of the diff of two values
8
+ # examples:
9
+ # - diff of { a: a } and {} is { a: { left: a, right: HashDeepDiff::NO_VALUE } }
10
+ # - diff of { a: a } and { a: b } is { a: { left: a, right: b } }
11
+ # - diff of {} and { a: b } is { a: { left: HashDeepDiff::NO_VALUE, right: b } }
12
+ class Delta
13
+ include ActsAsHash
14
+
15
+ # Visual representation of additions and deletiond at given +path+
16
+ # @return [String]
17
+ def to_str
18
+ [deletion, addition].compact.join("\n")
19
+ end
20
+
21
+ # Returns true if we have nested Hashes
22
+ # @return [Bool]
23
+ def complex?
24
+ left.respond_to?(:to_hash) && right.respond_to?(:to_hash)
25
+ end
26
+
27
+ # Keys needed to fetch values that we're comparing
28
+ # @return [Array]
29
+ def path
30
+ @prefix + [@delta.keys.first]
31
+ end
32
+
33
+ # Original value
34
+ def left
35
+ @value[:left]
36
+ end
37
+
38
+ # Value we compare to
39
+ def right
40
+ @value[:right]
41
+ end
42
+
43
+ # See {#to_str}
44
+ def to_s
45
+ to_str
46
+ end
47
+
48
+ private
49
+
50
+ # @param [Array, Object] path list of keys to fetch values we're comparing
51
+ # @param [Hash<(:left, :right), Object>] value +Hash+ object with two keys - :left and :right,
52
+ # 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
65
+ end
66
+
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)
73
+ end
74
+
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)
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,53 @@
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
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module HashDeepDiff
4
- VERSION = '0.3.3'
4
+ # Version of a gem
5
+ VERSION = '0.5.0'
5
6
  end
@@ -3,6 +3,8 @@
3
3
  require 'hash_deep_diff/version'
4
4
  require 'hash_deep_diff/comparison'
5
5
 
6
+ # Global namespace
6
7
  module HashDeepDiff
7
- class Error < StandardError; end
8
+ # value was not found
9
+ NO_VALUE = Class.new(NilClass)
8
10
  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.5.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-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 1.17.2
19
+ version: 2.3.11
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 1.17.2
26
+ version: 2.3.11
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: guard
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: 1.5.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: guard-yard
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 2.2.1
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 2.2.1
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: minitest
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -173,10 +187,14 @@ extra_rdoc_files: []
173
187
  files:
174
188
  - ".bundle/.keep"
175
189
  - ".bundle/config"
190
+ - ".github/workflows/ci.yml"
176
191
  - ".gitignore"
177
192
  - ".rubocop.yml"
193
+ - ".yardopts"
194
+ - CHANGELOG.md
178
195
  - Gemfile
179
196
  - Guardfile
197
+ - MIT-LICENSE
180
198
  - README.md
181
199
  - Rakefile
182
200
  - bin/_guard-core
@@ -186,13 +204,15 @@ files:
186
204
  - bin/rake
187
205
  - bin/rubocop
188
206
  - bin/setup
207
+ - bin/yard
208
+ - bin/yardoc
209
+ - bin/yri
189
210
  - hash_deep_diff.gemspec
190
211
  - lib/hash_deep_diff.rb
212
+ - lib/hash_deep_diff/acts_as_hash.rb
191
213
  - 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
214
+ - lib/hash_deep_diff/delta.rb
215
+ - lib/hash_deep_diff/report.rb
196
216
  - lib/hash_deep_diff/version.rb
197
217
  homepage: https://github.com/bpohoriletz/hash_deep_diff
198
218
  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