hana
Crystal port of the Ruby gem [hana]3.
Implementation of [JSON Patch]1 (RFC 6902) and [JSON Pointer]2 (RFC 6901).
Installation
-
Add the dependency to your
shard.yml:dependencies: hana: github: cyangle/hana.cr version: ~> 0.1.1 -
Run
shards install
Requirements: Crystal >= 1.13.2
Usage
JSON Patch
Apply patches to JSON documents. Supports all RFC 6902 operations: add, remove, replace, move, copy, and test.
require "hana"
doc = JSON.parse(%({
"name": "John",
"age": 30,
"tags": ["developer"]
}))
# Create patch from JSON string
patch = Hana::Patch.new(%([
{ "op": "replace", "path": "/name", "value": "Jane" },
{ "op": "add", "path": "/email", "value": "[email protected]" },
{ "op": "remove", "path": "/age" },
{ "op": "add", "path": "/tags/-", "value": "designer" }
]))
result = patch.apply(doc)
puts result.to_json
# {"name":"Jane","tags":["developer","designer"],"email":"[email protected]"}
Patch Operations
| Operation | Description | Example |
|-----------|-------------|---------|
| add | Add a value | {"op": "add", "path": "/foo", "value": "bar"} |
| remove | Remove a value | {"op": "remove", "path": "/foo"} |
| replace | Replace a value | {"op": "replace", "path": "/foo", "value": "baz"} |
| move | Move a value | {"op": "move", "from": "/foo", "path": "/bar"} |
| copy | Copy a value | {"op": "copy", "from": "/foo", "path": "/bar"} |
| test | Test a value matches | {"op": "test", "path": "/foo", "value": "bar"} |
Creating Patches
# From JSON string
patch = Hana::Patch.new(%([{"op": "add", "path": "/foo", "value": "bar"}]))
# From IO
patch = Hana::Patch.new(File.open("patches.json"))
# From Array
ops = [{"op" => JSON::Any.new("add"), "path" => JSON::Any.new("/foo"), "value" => JSON::Any.new("bar")}]
patch = Hana::Patch.new(ops)
JSON Pointer
Evaluate JSON Pointers to extract values from JSON documents.
require "hana"
doc = JSON.parse(%({
"users": [
{"name": "Alice", "role": "admin"},
{"name": "Bob", "role": "user"}
],
"config": {
"debug": true
}
}))
# Get nested values
pointer = Hana::Pointer.new("/users/0/name")
puts pointer.eval(doc) # "Alice"
pointer = Hana::Pointer.new("/users/1/role")
puts pointer.eval(doc) # "user"
pointer = Hana::Pointer.new("/config/debug")
puts pointer.eval(doc) # true
Development
hana runs tests from json-patch/json-patch-tests. Fetch the git submodule by running:
git submodule init
git submodule update
Install dependencies with:
shards install
Then run the tests with:
crystal spec
Linting
Format code with Crystal's built-in formatter:
crystal tool format
Run static analysis with Ameba:
bin/ameba
Contributing
- Fork it (https://github.com/cyangle/hana.cr/fork)
- Create your feature branch (
git checkout -b my-new-feature) - Commit your changes (
git commit -am 'Add some feature') - Push to the branch (
git push origin my-new-feature) - Create a new Pull Request
Contributors
- Chao Yang - creator and maintainer
License
This project is licensed under the MIT License - see the LICENSE file for details.