Skip to content

Commit

Permalink
Merge pull request #93 from MatzFan/ignore_keys_fix
Browse files Browse the repository at this point in the history
fix #88 bug in ignore_keys option
  • Loading branch information
liufengyun committed Aug 2, 2024
2 parents 1579751 + 945a87d commit a290c7f
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 21 deletions.
23 changes: 13 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,22 +119,25 @@ The `:strict` option, which defaults to `true`, specifies whether numeric types

#### `:ignore_keys`

The `:ignore_keys` option allows you to specify one or more keys to ignore, which defaults to `[]` (none). Ignored keys are ignored at all levels. For example:
The `:ignore_keys` option allows you to specify one or more keys to ignore, which defaults to `[]` (none). Ignored keys are ignored at all levels in both hashes. For example:

```ruby
a = { a: 1, b: { d: 2, a: 3 }, c: 4 }
b = { a: 2, b: { d: 2, a: 7 }, c: 5 }
diff = Hashdiff.diff(a, b, ignore_keys: :a)
diff.should == [['~', 'c', 4, 5]]
a = { a: 4, g: 0, b: { a: 5, c: 6, e: 1 } }
b = { b: { a: 7, c: 3, f: 1 }, d: 8 }
diff = Hashdiff.diff(a, b, ignore_keys: %i[a f])
diff.should == [['-', 'g', 0], ['-', 'b.e', 1], ['~', 'b.c', 6, 3], ['+', 'd', 8]]
```
If you wish instead to ignore keys at a particlar level you should
use a [custom comparison method](https://github.com/liufengyun/hashdiff#specifying-a-custom-comparison-method) instead. For example:
use a [custom comparison method](https://github.com/liufengyun/hashdiff#specifying-a-custom-comparison-method) instead. For example to diff only at the 2nd level of both hashes:

```ruby
a = { a: 1, b: { d: 2, a: 3 }, c: 4 }
b = { a: 2, b: { d: 2, a: 7 }, c: 5 }
diff = Hashdiff.diff(a, b) { |path, _e, _a| true if path == 'b.a' } # note '.' is the default delimiter
diff.should == [['~', 'a', 1, 2], ['~', 'c', 4, 5]]
a = { a: 4, g: 0, b: { a: 5, c: 6, e: 1 } }
b = { b: { a: 7, c: 3, f: 1 }, d: 8 }
diff = Hashdiff.diff(a, b) do |path, _e, _a|
arr = path.split('.')
true if %w[a f].include?(arr.last) && arr.size == 2 # note '.' is the default delimiter
end
diff.should == [['-', 'a', 4], ['-', 'g', 0], ['-', 'b.e', 1], ['~', 'b.c', 6, 3], ['+', 'd', 8]]
```

#### `:indifferent`
Expand Down
2 changes: 2 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Change Log

* Fix bug in ignore_keys option #88

## v1.1.0 2023-12-14

* Add ignore_keys option (#86 @Matzfan)
Expand Down
6 changes: 5 additions & 1 deletion lib/hashdiff/compare_hashes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,11 @@ def call(obj1, obj2, opts = {})

result = []

opts[:ignore_keys].each { |k| common_keys.delete k }
opts[:ignore_keys].each do |k|
added_keys.delete k
common_keys.delete k
deleted_keys.delete k
end

# add deleted properties
deleted_keys.each do |k|
Expand Down
6 changes: 3 additions & 3 deletions lib/hashdiff/diff.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ module Hashdiff
# @param [Array, Hash] obj2
# @param [Hash] options the options to use when comparing
# * :strict (Boolean) [true] whether numeric values will be compared on type as well as value. Set to false to allow comparing Integer, Float, BigDecimal to each other
# * :ignore_keys (Symbol, String or Array) [[]] a list of keys to ignore. No comparison is made for the specified key(s)
# * :ignore_keys (Symbol, String or Array) [[]] a list of keys to ignore. No comparison is made for the specified key(s) in either hash
# * :indifferent (Boolean) [false] whether to treat hash keys indifferently. Set to true to ignore differences between symbol keys (ie. {a: 1} ~= {'a' => 1})
# * :delimiter (String) ['.'] the delimiter used when returning nested key references
# * :numeric_tolerance (Numeric) [0] should be a positive numeric value. Value by which numeric differences must be greater than. By default, numeric values are compared exactly; with the :tolerance option, the difference between numeric values must be greater than the given value.
Expand Down Expand Up @@ -54,7 +54,7 @@ def self.best_diff(obj1, obj2, options = {}, &block)
# @param [Array, Hash] obj2
# @param [Hash] options the options to use when comparing
# * :strict (Boolean) [true] whether numeric values will be compared on type as well as value. Set to false to allow comparing Integer, Float, BigDecimal to each other
# * :ignore_keys (Symbol, String or Array) [[]] a list of keys to ignore. No comparison is made for the specified key(s)
# * :ignore_keys (Symbol, String or Array) [[]] a list of keys to ignore. No comparison is made for the specified key(s) in either hash
# * :indifferent (Boolean) [false] whether to treat hash keys indifferently. Set to true to ignore differences between symbol keys (ie. {a: 1} ~= {'a' => 1})
# * :similarity (Numeric) [0.8] should be between (0, 1]. Meaningful if there are similar hashes in arrays. See {best_diff}.
# * :delimiter (String) ['.'] the delimiter used when returning nested key references
Expand Down Expand Up @@ -93,7 +93,7 @@ def self.diff(obj1, obj2, options = {}, &block)

opts[:prefix] = [] if opts[:array_path] && opts[:prefix] == ''

opts[:ignore_keys] = [*opts[:ignore_keys]] # splat covers single sym/string case
opts[:ignore_keys] = [*opts[:ignore_keys]]

opts[:comparison] = block if block_given?

Expand Down
34 changes: 27 additions & 7 deletions spec/hashdiff/diff_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,17 +50,37 @@
end

context 'with the ignore_keys option' do
a = { a: 1, b: { d: 2, a: 3 }, c: 4 }
b = { a: 2, b: { d: 2, a: 7 }, c: 5 }
a = { a: 4, g: 0, b: { a: 5, c: 6, e: 1 } }
b = { b: { a: 7, c: 3, f: 1 }, d: 8 }

it 'ignores a single key' do
it 'ignores a single key at first level' do
diff = described_class.diff(a, b, ignore_keys: :d)
diff.should == [['-', 'a', 4], ['-', 'g', 0], ['-', 'b.e', 1], ['~', 'b.a', 5, 7], ['~', 'b.c', 6, 3], ['+', 'b.f', 1]]
end

it 'ignores a single key in nested hash' do
diff = described_class.diff(a, b, ignore_keys: :e)
diff.should == [['-', 'a', 4], ['-', 'g', 0], ['~', 'b.a', 5, 7], ['~', 'b.c', 6, 3], ['+', 'b.f', 1], ['+', 'd', 8]]
end

it 'ignores a single key at all levels' do
diff = described_class.diff(a, b, ignore_keys: :a)
diff.should == [['~', 'c', 4, 5]]
diff.should == [['-', 'g', 0], ['-', 'b.e', 1], ['~', 'b.c', 6, 3], ['+', 'b.f', 1], ['+', 'd', 8]]
end

it 'ignores an array of keys' do
diff = described_class.diff(a, b, ignore_keys: %i[a c])
diff.should == []
it 'ignores an array of keys at first level' do
diff = described_class.diff(a, b, ignore_keys: %i[g b])
diff.should == [['-', 'a', 4], ['+', 'd', 8]]
end

it 'ignores an array of keys in nested hash' do
diff = described_class.diff(a, b, ignore_keys: %i[c e])
diff.should == [['-', 'a', 4], ['-', 'g', 0], ['~', 'b.a', 5, 7], ['+', 'b.f', 1], ['+', 'd', 8]]
end

it 'ignores an array of keys at all levels' do
diff = described_class.diff(a, b, ignore_keys: %i[a f])
diff.should == [['-', 'g', 0], ['-', 'b.e', 1], ['~', 'b.c', 6, 3], ['+', 'd', 8]]
end
end

Expand Down

0 comments on commit a290c7f

Please sign in to comment.