philiprehberger-differ 0.5.0 → 0.6.0

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: f6f6c2e127be0912f009924625aa0ef3babcc21855bb9a6f0af744f6c6dff179
4
- data.tar.gz: c2c99a65ed6ad72b399f52c99a3ac5866ca0c7705917c395124281c570869d31
3
+ metadata.gz: 43183caae823c98d43466bf7d1e6a2a5c993dc9f573d3d07352f3802fbc1b6d0
4
+ data.tar.gz: a7633ce9d9a19b69229548221475b8890198c272edf0bbb4e9d3fd3aae9eb912
5
5
  SHA512:
6
- metadata.gz: 9e3c7e4dcfabefe06c2348f4e13a1fa3023234ac3e57c2e8c3ac51437027944c906bfe3bc721e57d259087381bba09ee734181b80a83ce69872e6be814d1e041
7
- data.tar.gz: 6796e028cb9a84341db6fc7952e79c692bbcd8d87dbb1af116da04fdd883785db8c63a0e80909940355aae65f993b31437eb69aaa2ab27805f372ed69841ea4c
6
+ metadata.gz: 97bea10cc3793229177af29091a41a7af415ef1c383150604bffc8492a4f4dc4c0f57d78d7cbc9241c86ba3f2fa0c41c5170aafc1098f9fbe8b2e47129799b25
7
+ data.tar.gz: 8d728725be558d50bc31124070f43e47a7980971c75d78bc9150877bcc6dde91c52b1191514134492bae5948eff763ca70f92c4e755bb2c18d5bfb854b959bca
data/CHANGELOG.md CHANGED
@@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.6.0] - 2026-05-01
11
+
12
+ ### Added
13
+ - `Philiprehberger::Differ.invert(changeset)` — return a changeset with additions/removals swapped and changed values reversed; lets callers compute the inverse diff without rerunning the comparator
14
+
10
15
  ## [0.5.0] - 2026-04-21
11
16
 
12
17
  ### Added
data/README.md CHANGED
@@ -125,6 +125,17 @@ changeset = Philiprehberger::Differ.diff(old_data, new_data)
125
125
  user_changes = Philiprehberger::Differ.subset(changeset, 'user')
126
126
  ```
127
127
 
128
+ ### Inverting a Diff
129
+
130
+ Return the inverse of a changeset — additions and removals swap, and
131
+ changed values are reversed. Applying the inverse undoes the original:
132
+
133
+ ```ruby
134
+ forward = Philiprehberger::Differ.diff(old_data, new_data)
135
+ reverse = Philiprehberger::Differ.invert(forward)
136
+ reverse.apply(forward.apply(old_data)) # => old_data
137
+ ```
138
+
128
139
  ### Three-Way Merge
129
140
 
130
141
  ```ruby
@@ -186,6 +197,7 @@ Returns a Float between 0.0 (completely different) and 1.0 (identical).
186
197
  | Method | Description |
187
198
  |---|---|
188
199
  | `Differ.subset(changeset, path)` | Filter changes to a specific path prefix |
200
+ | `Differ.invert(changeset)` | Return a new changeset that reverses the original |
189
201
  | `Differ.merge(base, theirs, ours)` | Three-way merge with conflict detection |
190
202
  | `Differ.breaking_changes?(changeset)` | Detect removals and type changes |
191
203
  | `.stats(changeset)` | Count summary of a changeset |
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Philiprehberger
4
4
  module Differ
5
- VERSION = '0.5.0'
5
+ VERSION = '0.6.0'
6
6
  end
7
7
  end
@@ -33,6 +33,40 @@ module Philiprehberger
33
33
  Changeset.new(filtered)
34
34
  end
35
35
 
36
+ # Return the inverse of a changeset.
37
+ #
38
+ # Additions become removals (and vice versa), and changed entries swap
39
+ # their old and new values. Applying the inverted changeset to a hash
40
+ # that has already had the original changeset applied will undo it
41
+ # without keeping the prior state around.
42
+ #
43
+ # @param changeset [Changeset] the changeset to invert
44
+ # @return [Changeset] a new changeset with each change reversed
45
+ # @raise [ArgumentError] if `changeset` is not a {Changeset}
46
+ def self.invert(changeset)
47
+ raise ArgumentError, 'changeset must be a Philiprehberger::Differ::Changeset' unless changeset.is_a?(Changeset)
48
+
49
+ reversed = changeset.changes.map do |change|
50
+ case change.type
51
+ when :added
52
+ Change.new(path: change.path, type: :removed, old_value: change.new_value)
53
+ when :removed
54
+ Change.new(path: change.path, type: :added, new_value: change.old_value)
55
+ when :changed
56
+ Change.new(
57
+ path: change.path,
58
+ type: :changed,
59
+ old_value: change.new_value,
60
+ new_value: change.old_value
61
+ )
62
+ else
63
+ change
64
+ end
65
+ end
66
+
67
+ Changeset.new(reversed)
68
+ end
69
+
36
70
  # Perform a three-way merge with conflict detection
37
71
  #
38
72
  # @param base [Hash] the common ancestor
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: philiprehberger-differ
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Philip Rehberger
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-04-21 00:00:00.000000000 Z
11
+ date: 2026-05-02 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A Ruby library for deep structural diffing of hashes, arrays, and nested
14
14
  objects with apply/revert, JSON Patch output, similarity scoring, and configurable