hash_deep_diff 0.1.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: []