hash_deep_diff 0.1.0 → 0.3.1

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: ba9a1f48817d357af97c44b197ca81ea20cd7c0b809ecf994c6d432ec281951f
4
- data.tar.gz: 065c3598e130199735f058a3d1530e220fcc7b36a662aa8cfba76b1ee5efef1a
3
+ metadata.gz: 43343dfc0eed6ad00b863b65b535f206b6a14544c8c23560f01954e16c7ef19b
4
+ data.tar.gz: 613e764bf1a0390bfba99eceaa6e65e69355903858c229f8d150661c8a923af4
5
5
  SHA512:
6
- metadata.gz: 3be4e4202cb560aaffe5beedcc7b0993d24e4083577f20ca7ab2403c5557331fa19affdfa953e349c98ce5df1c963ba8d966b2fc420916e3ec533c9a41a67867
7
- data.tar.gz: 15ba966943ca6b67fdd294a2e9f47d5ea04470d78632cd193cb065c3762f44d689586222add5197152d6ff8684d74637add0f2d8a531b84a39bee46dfaf507dc
6
+ metadata.gz: 701aad97711690dbaff2719a3c0f6a4c0bbbf2a3ffdcd088b6451803c392a019dd37dba9b3cffc3a7843862b8341d6a7e17eaa2935aba8be4f069fb81160a052
7
+ data.tar.gz: 920a5d22b16bb78866c752c5a60469f37af9d58f8f0f3852c1822f594223f995ed4c87f14777d3dc857a73310d1c851581edd9fdba36bc3b433d069133211d95
data/.bundle/.keep ADDED
File without changes
data/.bundle/config ADDED
@@ -0,0 +1,2 @@
1
+ ---
2
+ BUNDLE_PATH: "vendor/bundle"
data/.gitignore CHANGED
@@ -1,4 +1,5 @@
1
- /.bundle/
1
+ *.gem
2
+ *.lock
2
3
  /.yardoc
3
4
  /_yardoc/
4
5
  /coverage/
@@ -6,3 +7,4 @@
6
7
  /pkg/
7
8
  /spec/reports/
8
9
  /tmp/
10
+ /vendor/bundle/
data/.rubocop.yml ADDED
@@ -0,0 +1,20 @@
1
+ require:
2
+ - rubocop/cop/internal_affairs
3
+ - rubocop-minitest
4
+ - rubocop-rake
5
+
6
+ AllCops:
7
+ NewCops: enable
8
+ Exclude:
9
+ - 'vendor/**/*'
10
+ - '.git/**/*'
11
+ - '.bundle/**/*'
12
+ - 'bin/*'
13
+
14
+ Style/RedundantReturn:
15
+ Enabled: false
16
+
17
+ Metrics/BlockLength:
18
+ Exclude:
19
+ - 'test/**/test_*.rb'
20
+ - '*.gemspec'
data/Gemfile CHANGED
@@ -1,6 +1,8 @@
1
- source "https://rubygems.org"
1
+ # frozen_string_literal: true
2
2
 
3
- git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
3
+ source 'https://rubygems.org'
4
+
5
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
4
6
 
5
7
  # Specify your gem's dependencies in hash_deep_diff.gemspec
6
8
  gemspec
data/Guardfile ADDED
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ # A sample Guardfile
4
+ # More info at https://github.com/guard/guard#readme
5
+
6
+ ## Uncomment and set this to only include directories you want to watch
7
+ # directories %w(app lib config test spec features) \
8
+ # .select{|d| Dir.exist?(d) ? d : UI.warning("Directory #{d} does not exist")}
9
+
10
+ ## Note: if you are using the `directories` clause above and you are not
11
+ ## watching the project directory ('.'), then you will want to move
12
+ ## the Guardfile to a watched dir and symlink it back, e.g.
13
+ #
14
+ # $ mkdir config
15
+ # $ mv Guardfile config/
16
+ # $ ln -s config/Guardfile .
17
+ #
18
+ # and, you'll have to watch "config/Guardfile" instead of "Guardfile"
19
+
20
+ guard :rubocop do
21
+ watch(/.+\.rb$/)
22
+ watch(/.+\.gemspec$/)
23
+ watch(%r{(?:.+/)?\.rubocop(?:_todo)?\.yml$}) { |m| File.dirname(m[0]) }
24
+ end
25
+
26
+ guard :minitest do
27
+ # with Minitest::Unit
28
+ watch(%r{^test/(.*)/?test_(.*)\.rb$})
29
+ # watch(%r{^lib/(.*/)?([^/]+)\.rb$}) { |m| "test/#{m[1]}test_#{m[2]}.rb" }
30
+ watch(%r{^lib/(.*/)?([^/]+)\.rb$}) { 'test' }
31
+ watch(%r{^test/test_helper\.rb$}) { 'test' }
32
+ watch(%r{^test/support/.*$}) { 'test' }
33
+ end
data/Rakefile CHANGED
@@ -1,2 +1,12 @@
1
- require "bundler/gem_tasks"
2
- task :default => :spec
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rake/testtask'
5
+
6
+ Rake::TestTask.new do |t|
7
+ t.libs << 'test'
8
+ t.test_files = FileList['test/**/*_spec.rb']
9
+ t.verbose = true
10
+ end
11
+
12
+ task default: :test
data/bin/_guard-core ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application '_guard-core' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require 'pathname'
12
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path('bundle', __dir__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require 'rubygems'
27
+ require 'bundler/setup'
28
+
29
+ load Gem.bin_path('guard', '_guard-core')
data/bin/bundle ADDED
@@ -0,0 +1,107 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'bundle' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require 'rubygems'
12
+
13
+ m = Module.new do
14
+ module_function
15
+
16
+ def invoked_as_script?
17
+ File.expand_path($PROGRAM_NAME) == File.expand_path(__FILE__)
18
+ end
19
+
20
+ def env_var_version
21
+ ENV['BUNDLER_VERSION']
22
+ end
23
+
24
+ def cli_arg_version
25
+ return unless invoked_as_script? # don't want to hijack other binstubs
26
+ return unless 'update'.start_with?(ARGV.first || ' ') # must be running `bundle update`
27
+
28
+ bundler_version = nil
29
+ update_index = nil
30
+ ARGV.each_with_index do |a, i|
31
+ bundler_version = a if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN
32
+ next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/
33
+
34
+ bundler_version = Regexp.last_match(1) || '>= 0.a'
35
+ update_index = i
36
+ end
37
+ bundler_version
38
+ end
39
+
40
+ def gemfile
41
+ gemfile = ENV['BUNDLE_GEMFILE']
42
+ return gemfile if gemfile && !gemfile.empty?
43
+
44
+ File.expand_path('../Gemfile', __dir__)
45
+ end
46
+
47
+ def lockfile
48
+ lockfile =
49
+ case File.basename(gemfile)
50
+ when 'gems.rb' then gemfile.sub(/\.rb$/, gemfile)
51
+ else "#{gemfile}.lock"
52
+ end
53
+ File.expand_path(lockfile)
54
+ end
55
+
56
+ def lockfile_version
57
+ return unless File.file?(lockfile)
58
+
59
+ lockfile_contents = File.read(lockfile)
60
+ return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/
61
+
62
+ Regexp.last_match(1)
63
+ end
64
+
65
+ def bundler_version
66
+ @bundler_version ||= env_var_version || cli_arg_version ||
67
+ lockfile_version || "#{Gem::Requirement.default}.a"
68
+ end
69
+
70
+ def load_bundler!
71
+ ENV['BUNDLE_GEMFILE'] ||= gemfile
72
+
73
+ # must dup string for RG < 1.8 compatibility
74
+ activate_bundler(bundler_version.dup)
75
+ end
76
+
77
+ def activate_bundler(bundler_version)
78
+ if Gem::Version.correct?(bundler_version) && Gem::Version.new(bundler_version).release < Gem::Version.new('2.0')
79
+ bundler_version = '< 2'
80
+ end
81
+ gem_error = activation_error_handling do
82
+ gem 'bundler', bundler_version
83
+ end
84
+ return if gem_error.nil?
85
+
86
+ require_error = activation_error_handling do
87
+ require 'bundler/version'
88
+ end
89
+ if require_error.nil? && Gem::Requirement.new(bundler_version).satisfied_by?(Gem::Version.new(Bundler::VERSION))
90
+ return
91
+ end
92
+
93
+ warn "Activating bundler (#{bundler_version}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_version}'`"
94
+ exit 42
95
+ end
96
+
97
+ def activation_error_handling
98
+ yield
99
+ nil
100
+ rescue StandardError, LoadError => e
101
+ e
102
+ end
103
+ end
104
+
105
+ m.load_bundler!
106
+
107
+ load Gem.bin_path('bundler', 'bundle') if m.invoked_as_script?
data/bin/console CHANGED
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
- require "bundler/setup"
4
- require "hash_deep_diff"
4
+ require 'bundler/setup'
5
+ require 'hash_deep_diff'
5
6
 
6
7
  # You can add fixtures and/or initialization code here to make experimenting
7
8
  # with your gem easier. You can also use a different console, if you like.
@@ -10,5 +11,5 @@ require "hash_deep_diff"
10
11
  # require "pry"
11
12
  # Pry.start
12
13
 
13
- require "irb"
14
+ require 'irb'
14
15
  IRB.start(__FILE__)
data/bin/guard ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'guard' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require 'pathname'
12
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path('bundle', __dir__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require 'rubygems'
27
+ require 'bundler/setup'
28
+
29
+ load Gem.bin_path('guard', 'guard')
data/bin/rake ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'rake' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require 'pathname'
12
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path('bundle', __dir__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require 'rubygems'
27
+ require 'bundler/setup'
28
+
29
+ load Gem.bin_path('rake', 'rake')
data/bin/rubocop ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'rubocop' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require 'pathname'
12
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path('bundle', __dir__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require 'rubygems'
27
+ require 'bundler/setup'
28
+
29
+ load Gem.bin_path('rubocop', 'rubocop')
@@ -1,41 +1,53 @@
1
+ # frozen_string_literal: true
1
2
 
2
- lib = File.expand_path("../lib", __FILE__)
3
+ lib = File.expand_path('lib', __dir__)
3
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require "hash_deep_diff/version"
5
+ require 'hash_deep_diff/version'
5
6
 
6
7
  Gem::Specification.new do |spec|
7
- spec.name = "hash_deep_diff"
8
+ spec.name = 'hash_deep_diff'
8
9
  spec.version = HashDeepDiff::VERSION
9
10
  spec.licenses = ['MIT']
10
- spec.authors = ["Bohdan Pohorilets"]
11
- spec.email = ["bohdan.pohorilets@gmail.com"]
11
+ spec.authors = ['Bohdan Pohorilets']
12
+ spec.email = ['bohdan.pohorilets@gmail.com']
12
13
 
13
- spec.summary = %q{Deep diff for ruby hashes.}
14
- spec.description = %q{Find the exact difference between two hashes.}
15
- spec.homepage = "https://github.com/bpohoriletz/hash_deep_diff"
14
+ spec.summary = 'Deep diff for Ruby Hash objects'
15
+ spec.description = 'Find the exact difference between two Hash objects'
16
+ spec.homepage = 'https://github.com/bpohoriletz/hash_deep_diff'
17
+ spec.required_ruby_version = '>= 2.6.1'
16
18
 
17
19
  # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
20
  # to allow pushing to a single host or delete this section to allow pushing to any host.
19
21
  if spec.respond_to?(:metadata)
20
- spec.metadata["allowed_push_host"] = "https://rubygems.org/"
22
+ spec.metadata['allowed_push_host'] = 'https://rubygems.org/'
21
23
 
22
- spec.metadata["homepage_uri"] = spec.homepage
23
- spec.metadata["source_code_uri"] = "https://github.com/bpohoriletz/hash_deep_diff"
24
- spec.metadata["changelog_uri"] = "https://github.com/bpohoriletz/hash_deep_diff/blob/main/CHANGELOG.md"
24
+ spec.metadata['homepage_uri'] = spec.homepage
25
+ spec.metadata['source_code_uri'] = 'https://github.com/bpohoriletz/hash_deep_diff'
26
+ spec.metadata['changelog_uri'] = 'https://github.com/bpohoriletz/hash_deep_diff/blob/main/CHANGELOG.md'
27
+ spec.metadata['rubygems_mfa_required'] = 'true'
25
28
  else
26
- raise "RubyGems 2.0 or newer is required to protect against " \
27
- "public gem pushes."
29
+ raise 'RubyGems 2.0 or newer is required to protect against ' \
30
+ 'public gem pushes.'
28
31
  end
29
32
 
30
33
  # Specify which files should be added to the gem when it is released.
31
34
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
32
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
35
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
33
36
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
34
37
  end
35
- spec.bindir = "exe"
38
+ spec.bindir = 'exe'
36
39
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
37
- spec.require_paths = ["lib"]
40
+ spec.require_paths = ['lib']
38
41
 
39
- spec.add_development_dependency "bundler", "~> 1.17"
40
- spec.add_development_dependency "rake", "~> 10.0"
42
+ spec.add_development_dependency 'bundler', '~> 1.17.2'
43
+ spec.add_development_dependency 'guard', '~> 2.18.0'
44
+ spec.add_development_dependency 'guard-minitest', '~> 2.4.6'
45
+ spec.add_development_dependency 'guard-rubocop', '~> 1.5.0'
46
+ spec.add_development_dependency 'minitest', '~> 5.15.0'
47
+ spec.add_development_dependency 'minitest-focus', '~> 1.3.1'
48
+ spec.add_development_dependency 'minitest-reporters', '~> 1.5.0'
49
+ spec.add_development_dependency 'rake', '~> 10.5.0'
50
+ spec.add_development_dependency 'rubocop', '~> 1.26.1'
51
+ spec.add_development_dependency 'rubocop-minitest', '~> 0.18.0'
52
+ spec.add_development_dependency 'rubocop-rake', '~> 0.6.0'
41
53
  end
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'delta/left'
4
+ require_relative 'delta/inner'
5
+ require_relative 'delta/right'
6
+
7
+ # :nodoc:
8
+ module HashDeepDiff
9
+ # :nodoc:
10
+ class Comparison
11
+ attr_reader :left, :right, :path
12
+
13
+ def diff(&block)
14
+ left_delta + deep_delta(&block) + right_delta
15
+ end
16
+
17
+ def report
18
+ diff.join("\n")
19
+ end
20
+
21
+ private
22
+
23
+ def initialize(left, right, path = [])
24
+ @left = left.to_hash
25
+ @right = right.to_hash
26
+ @path = path.to_ary
27
+ end
28
+
29
+ def extra_report(memo, keys, value)
30
+ if value.respond_to?(:to_hash)
31
+ value.each_key { |key| extra_report(memo, keys + [key], value[key]) }
32
+ else
33
+ memo << Delta::Left.new(path: keys, value: value)
34
+ end
35
+ end
36
+
37
+ def missing_report(memo, keys, value)
38
+ if value.respond_to?(:to_hash)
39
+ value.each_key { |key| missing_report(memo, keys + [key], value[key]) }
40
+ else
41
+ memo << Delta::Right.new(path: keys, value: value)
42
+ end
43
+ end
44
+
45
+ def delta_report(memo, keys, value)
46
+ if value.respond_to?(:to_hash) && value.keys != %i[left right]
47
+ value.each_key { |key| delta_report(memo, keys + [key], value[key]) }
48
+ elsif value.instance_of?(Array) && value.size == 3 && value.all? { |el| el.respond_to?(:to_hash) }
49
+ # [{}, {}, {:i=>:i}]
50
+ extra_report(memo, keys, value[0]) unless value[0].empty?
51
+ delta_report(memo, keys, value[1]) unless value[1].empty?
52
+ missing_report(memo, keys, value[2]) unless value[2].empty?
53
+ else
54
+ memo << Delta::Inner.new(path: keys, value: value)
55
+ end
56
+ end
57
+
58
+ def deep_delta(&block)
59
+ result = delta(&block)
60
+
61
+ result.each_with_object([]) do |diff, memo|
62
+ if left.dig(*diff.path).respond_to?(:to_hash) && right.dig(*diff.path).respond_to?(:to_hash)
63
+ self.class.new(left.dig(*diff.path), right.dig(*diff.path), path + diff.path).diff.each do |diff|
64
+ memo << diff
65
+ end
66
+ else
67
+ memo << diff
68
+ end
69
+ end
70
+ end
71
+
72
+ def right_delta
73
+ right_diff_keys.map { |key| Delta::Right.new(path: path + [key], value: right[key]) }
74
+ end
75
+
76
+ def delta(&block)
77
+ block ||= ->(val) { val }
78
+
79
+ common_keys.each_with_object([]) do |key, memo|
80
+ value_left = block.call(left[key])
81
+ value_right = block.call(right[key])
82
+
83
+ next if value_right.instance_of?(value_left.class) && (value_right == value_left)
84
+
85
+ memo << Delta::Inner.new(path: path + [key], value: { left: value_left, right: value_right })
86
+ end
87
+ end
88
+
89
+ def left_delta
90
+ left_diff_keys.map { |key| Delta::Left.new(path: path + [key], value: left[key]) }
91
+ end
92
+
93
+ def common_keys
94
+ left.keys & right.keys
95
+ end
96
+
97
+ def right_diff_keys
98
+ right.keys - left.keys
99
+ end
100
+
101
+ def left_diff_keys
102
+ left.keys - right.keys
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,62 @@
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
+ def path
27
+ @prefix + [@delta.keys.first]
28
+ end
29
+
30
+ def to_h
31
+ @delta
32
+ end
33
+
34
+ def to_hash
35
+ @delta
36
+ end
37
+
38
+ def to_s
39
+ to_str
40
+ end
41
+
42
+ def to_str
43
+ raise NoMethodError, "expected #{self.class} to implement #to_str"
44
+ end
45
+ end
46
+
47
+ # Override #initialize method
48
+ module Initialize
49
+ def initialize(path:, value:)
50
+ # TOFIX this may prohibit usage of hashes with Array keys
51
+ if path.respond_to?(:to_ary)
52
+ @delta = { path[-1] => value }
53
+ @prefix = path[0..-2]
54
+ else
55
+ @delta = { path => value }
56
+ @prefix = []
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,44 @@
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
+ if @delta.values.first.respond_to?(:to_hash)
15
+ if @delta.values.first.keys == %i[left right]
16
+ if @delta.values.first[:left].respond_to?(:to_hash) && @delta.values.first[:right].respond_to?(:to_hash)
17
+ HashDeepDiff::Comparison.new(
18
+ @delta.values.first[:left],
19
+ @delta.values.first[:right],
20
+ path
21
+ ).report
22
+ else
23
+ lines = <<~Q
24
+ -left#{diff_prefix} = #{@delta.values.first[:left]}
25
+ +right#{diff_prefix} = #{@delta.values.first[:right]}
26
+ Q
27
+ lines.strip
28
+ end
29
+ else
30
+ @delta.values.first.keys.map do |key|
31
+ self.class.new(path: path + [key], value: @delta.values.first[key])
32
+ end.join("\n").strip
33
+ end
34
+ else
35
+ lines = <<~Q
36
+ -left#{diff_prefix} = #{@delta.values.first[:left]}
37
+ +right#{diff_prefix} = #{@delta.values.first[:right]}
38
+ Q
39
+ lines.strip
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,24 @@
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
+ if @delta.values.first.respond_to?(:to_hash)
15
+ @delta.values.first.keys.map do |key|
16
+ self.class.new(path: path + [key], value: @delta.values.first[key])
17
+ end.join("\n").strip
18
+ else
19
+ "+left#{diff_prefix} = #{@delta.values.first}"
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,24 @@
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
+ if @delta.values.first.respond_to?(:to_hash)
15
+ @delta.values.first.keys.map do |key|
16
+ self.class.new(path: path + [key], value: @delta.values.first[key])
17
+ end.join("\n").strip
18
+ else
19
+ "-left#{diff_prefix} = #{@delta.values.first}"
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module HashDeepDiff
2
- VERSION = "0.1.0"
4
+ VERSION = '0.3.1'
3
5
  end
@@ -1,6 +1,8 @@
1
- require "hash_deep_diff/version"
1
+ # frozen_string_literal: true
2
+
3
+ require 'hash_deep_diff/version'
4
+ require 'hash_deep_diff/comparison'
2
5
 
3
6
  module HashDeepDiff
4
7
  class Error < StandardError; end
5
- # Your code goes here...
6
8
  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.1.0
4
+ version: 0.3.1
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-03-30 00:00:00.000000000 Z
11
+ date: 2022-04-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -16,43 +16,183 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.17'
19
+ version: 1.17.2
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'
26
+ version: 1.17.2
27
+ - !ruby/object:Gem::Dependency
28
+ name: guard
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 2.18.0
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 2.18.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: guard-minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 2.4.6
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 2.4.6
55
+ - !ruby/object:Gem::Dependency
56
+ name: guard-rubocop
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 1.5.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 1.5.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: minitest
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 5.15.0
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 5.15.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: minitest-focus
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 1.3.1
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 1.3.1
97
+ - !ruby/object:Gem::Dependency
98
+ name: minitest-reporters
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 1.5.0
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 1.5.0
27
111
  - !ruby/object:Gem::Dependency
28
112
  name: rake
29
113
  requirement: !ruby/object:Gem::Requirement
30
114
  requirements:
31
115
  - - "~>"
32
116
  - !ruby/object:Gem::Version
33
- version: '10.0'
117
+ version: 10.5.0
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 10.5.0
125
+ - !ruby/object:Gem::Dependency
126
+ name: rubocop
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: 1.26.1
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: 1.26.1
139
+ - !ruby/object:Gem::Dependency
140
+ name: rubocop-minitest
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: 0.18.0
34
146
  type: :development
35
147
  prerelease: false
36
148
  version_requirements: !ruby/object:Gem::Requirement
37
149
  requirements:
38
150
  - - "~>"
39
151
  - !ruby/object:Gem::Version
40
- version: '10.0'
41
- description: Find the exact difference between two hashes.
152
+ version: 0.18.0
153
+ - !ruby/object:Gem::Dependency
154
+ name: rubocop-rake
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: 0.6.0
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: 0.6.0
167
+ description: Find the exact difference between two Hash objects
42
168
  email:
43
169
  - bohdan.pohorilets@gmail.com
44
170
  executables: []
45
171
  extensions: []
46
172
  extra_rdoc_files: []
47
173
  files:
174
+ - ".bundle/.keep"
175
+ - ".bundle/config"
48
176
  - ".gitignore"
177
+ - ".rubocop.yml"
49
178
  - Gemfile
179
+ - Guardfile
50
180
  - README.md
51
181
  - Rakefile
182
+ - bin/_guard-core
183
+ - bin/bundle
52
184
  - bin/console
185
+ - bin/guard
186
+ - bin/rake
187
+ - bin/rubocop
53
188
  - bin/setup
54
189
  - hash_deep_diff.gemspec
55
190
  - lib/hash_deep_diff.rb
191
+ - 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
56
196
  - lib/hash_deep_diff/version.rb
57
197
  homepage: https://github.com/bpohoriletz/hash_deep_diff
58
198
  licenses:
@@ -62,6 +202,7 @@ metadata:
62
202
  homepage_uri: https://github.com/bpohoriletz/hash_deep_diff
63
203
  source_code_uri: https://github.com/bpohoriletz/hash_deep_diff
64
204
  changelog_uri: https://github.com/bpohoriletz/hash_deep_diff/blob/main/CHANGELOG.md
205
+ rubygems_mfa_required: 'true'
65
206
  post_install_message:
66
207
  rdoc_options: []
67
208
  require_paths:
@@ -70,7 +211,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
70
211
  requirements:
71
212
  - - ">="
72
213
  - !ruby/object:Gem::Version
73
- version: '0'
214
+ version: 2.6.1
74
215
  required_rubygems_version: !ruby/object:Gem::Requirement
75
216
  requirements:
76
217
  - - ">="
@@ -80,5 +221,5 @@ requirements: []
80
221
  rubygems_version: 3.0.3
81
222
  signing_key:
82
223
  specification_version: 4
83
- summary: Deep diff for ruby hashes.
224
+ summary: Deep diff for Ruby Hash objects
84
225
  test_files: []