philiprehberger-json_merge
JSON Merge Patch (RFC 7396) and JSON Patch (RFC 6902) for Ruby
Requirements
- Ruby >= 3.1
Installation
Add to your Gemfile:
gem "philiprehberger-json_merge"
Or install directly:
gem install philiprehberger-json_merge
Usage
require "philiprehberger/json_merge"
RFC 7396 Merge Patch
target = { "a" => 1, "b" => 2 }
patch = { "b" => 3, "c" => 4 }
Philiprehberger::JsonMerge.merge_patch(target, patch)
# => {"a"=>1, "b"=>3, "c"=>4}
Remove keys with nil:
Philiprehberger::JsonMerge.merge_patch({ "a" => 1, "b" => 2 }, { "b" => nil })
# => {"a"=>1}
RFC 6902 JSON Patch
doc = { "name" => "Alice", "age" => 30 }
ops = [
{ "op" => "replace", "path" => "/name", "value" => "Bob" },
{ "op" => "add", "path" => "/active", "value" => true },
{ "op" => "remove", "path" => "/age" }
]
Philiprehberger::JsonMerge.apply(doc, ops)
# => {"name"=>"Bob", "active"=>true}
Generate Patches
RFC 6902 diff:
source = { "a" => 1, "b" => 2 }
target = { "a" => 1, "b" => 3, "c" => 4 }
Philiprehberger::JsonMerge.diff(source, target)
# => [{"op"=>"replace", "path"=>"/b", "value"=>3}, {"op"=>"add", "path"=>"/c", "value"=>4}]
RFC 7396 merge diff:
Philiprehberger::JsonMerge.merge_diff(source, target)
# => {"b"=>3, "c"=>4}
Validate
Dry-run patch operations without modifying the document:
result = Philiprehberger::JsonMerge.validate(target, operations)
result[:valid] # => true/false
result[:errors] # => ["Operation 0 (remove /missing): ..."]
Invert
Generate reverse operations to undo a patch:
inverse = Philiprehberger::JsonMerge.invert(target, operations)
restored = Philiprehberger::JsonMerge.apply(patched, inverse)
restored == target # => true
Compact
Remove redundant operations:
optimized = Philiprehberger::JsonMerge.compact(operations)
Paths affected by a patch
Get the sorted, deduplicated list of document paths that a patch sequence would touch. For move and copy ops the from location is included alongside path:
ops = [
{ "op" => "replace", "path" => "/name", "value" => "Bob" },
{ "op" => "move", "from" => "/age", "path" => "/years" },
{ "op" => "add", "path" => "/name", "value" => "Bob" }
]
Philiprehberger::JsonMerge.paths(ops)
# => ["/age", "/name", "/years"]
API
| Method | Description |
|---|---|
JsonMerge.merge_patch(target, patch) |
Apply RFC 7396 merge patch |
JsonMerge.apply(target, operations) |
Apply RFC 6902 JSON Patch |
JsonMerge.diff(source, target) |
Generate RFC 6902 patch operations |
JsonMerge.merge_diff(source, target) |
Generate RFC 7396 merge patch |
JsonMerge.validate(target, ops) |
Dry-run operations, return { valid:, errors: } |
JsonMerge.invert(target, ops) |
Generate reverse operations to undo a patch |
JsonMerge.compact(ops) |
Remove redundant operations |
JsonMerge.paths(ops) |
List sorted, deduplicated paths a patch touches (includes from for move/copy) |
Development
bundle install
bundle exec rspec # Run tests
bundle exec rubocop # Check code style
Support
If you find this project useful: