Skip to content

Commit

Permalink
Improve docs & codecov for 0.5.0 (#56)
Browse files Browse the repository at this point in the history
* improves documentation
* brings code coverage to 99%
* fixes `TryFrom` for `Index`
* adds `FromStr` for `Index`
---------

Co-authored-by: André Mello <[email protected]>
  • Loading branch information
chanced and asmello authored Jul 9, 2024
1 parent a67948d commit 89bfee5
Show file tree
Hide file tree
Showing 16 changed files with 1,800 additions and 703 deletions.
5 changes: 5 additions & 0 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[alias]
cov = "llvm-cov --lcov --output-path lcov.info"

[build]
rustdocflags = ["--cfg", "docsrs"]
28 changes: 15 additions & 13 deletions .github/codecov.yml
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
# ref: https://docs.codecov.com/docs/codecovyml-reference
coverage:
# Hold ourselves to a high bar
range: 85..100
round: down
precision: 1
status:
# ref: https://docs.codecov.com/docs/commit-status
project:
default:
# Avoid false negatives
threshold: 1%
# Hold ourselves to a high bar
range: 85..100
round: down
precision: 1
status:
# ref: https://docs.codecov.com/docs/commit-status
project:
default:
# Avoid false negatives
threshold: 1%

# Test files aren't important for coverage
ignore:
- "tests"
- "tests"
- "arbitrary.rs"
- "src/arbitrary.rs"

# Make comments less noisy
comment:
layout: "files"
require_changes: true
layout: "files"
require_changes: true
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
/target
# Cargo.lock
lcov.info
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ This is a breaking release including:
- [Quickcheck](https://docs.rs/quickcheck/latest/quickcheck/index.html)-based testing
- New methods: `Pointer::split_front`, `Pointer::split_back`, `Pointer::parent`, `Pointer::strip_suffix`
- Implemented `Display` and `Debug` for `ParseError`
- Adds `Pointer::split_at` which utilizes character offsets to split a pointer at a seperator
- Adds `Pointer::split_at` which utilizes character offsets to split a pointer at a separator
- Adds specific error types `ParseError`, `ResolveError`, `AssignError`

### Changed
Expand Down
1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ syn = { version = "1.0.109", optional = true }
assign = []
default = ["std", "serde", "json", "resolve", "assign", "delete"]
delete = ["resolve"]
impl = []
json = ["dep:serde_json", "serde"]
resolve = []
std = ["serde/std", "serde_json?/std"]
Expand Down
205 changes: 119 additions & 86 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,131 +1,164 @@
# jsonptr - JSON Pointers for Rust
<div class="rustdoc-hidden">

# jsonptr - JSON Pointers (RFC 6901) for Rust

</div>

[<img alt="github" src="https://img.shields.io/badge/github-chanced/jsonptr-62D1FC?style=for-the-badge&labelColor=777&logo=github" height="21">](https://github.com/chanced/jsonptr)
[<img alt="crates.io" src="https://img.shields.io/crates/v/jsonptr.svg?style=for-the-badge&color=fc8d62&logo=rust" height="21">](https://crates.io/crates/jsonptr)
[<img alt="docs.rs" src="https://img.shields.io/badge/docs.rs-jsonptr-f0f0f0?style=for-the-badge&labelColor=777&logo=docs.rs" height="21">](https://docs.rs/jsonptr)
[<img alt="build status" src="https://img.shields.io/github/actions/workflow/status/chanced/jsonptr/test.yml?branch=main&style=for-the-badge" height="21">](https://github.com/chanced/jsonptr/actions?query=branch%3Amain)
[<img alt="code coverage" src="https://img.shields.io/codecov/c/github/chanced/jsonptr?style=for-the-badge&color=CBB88D" height="21">](https://codecov.io/gh/chanced/jsonptr)

Data structures and logic for resolving, assigning, and deleting by JSON Pointers ([RFC
6901](https://datatracker.ietf.org/doc/html/rfc6901)).
JSON Pointers ([RFC 6901](https://datatracker.ietf.org/doc/html/rfc6901))
defines a string syntax for identifying a specific location within a JSON, or
similar, document. This crate provides two types, [`Pointer`] and [`PointerBuf`]
(akin to [`Path`] and [`PathBuf`]), for working with them abstractly.

A pointer is composed of zero or more [`Token`]s, single segments which
represent a field of an object or an [`index`] of an array, and are bounded by
either `'/'` or the end of the string. Tokens are lightly encoded, where `'~'`
is escaped as `"~0"` due to it signaling encoding and `'/'` is escaped as `"~1"`
because `'/'` separates tokens and would split the token into two otherwise.

[`Token`]s can be iterated over using either [`Tokens`], returned from the
[`tokens`] method of a pointer or [`Components`], returned from the
[`components`] method. The difference being that `Tokens` iterates over each
token in the pointer, while `Components` iterates over [`Component`]s, which can
represent the root of the document or a single token along with the offset of
the token from within the pointer.

Operations [`resolve`], [`assign`] and [`delete`] are provided as traits with
corresponding methods on pointer types. Implementations of each trait are
provided for value types of the crates [`serde_json`] and [`toml`]. All
operations are enabled by default but are gated by [feature
flags](#feature-flags).

## Usage

JSON Pointers can be created either with a slice of strings or directly from a properly encoded string representing a JSON Pointer.

### Resolve values

#### `Pointer::resolve`
To parse a pointer from a string, use the [`parse`](Pointer::parse) method.
[`PointerBuf`] can use either the [`parse`](PointerBuf::parse) or
[`from_tokens`](PointerBuf::from_tokens) construct from an iterator of
[`Token`]s:

```rust
use jsonptr::Pointer;
use jsonptr::{Pointer, PointerBuf};
use serde_json::json;

let mut data = json!({ "foo": { "bar": "baz" } });
let ptr = Pointer::from_static("/foo/bar");
let bar = ptr.resolve(&data).unwrap();
assert_eq!(bar, "baz");
```
let ptr = Pointer::parse("/examples/0/name").unwrap();

#### `Resolve::resolve`
let buf = PointerBuf::from_tokens(["examples", "0", "name"]);
assert_eq!(ptr, &buf);

```rust
use jsonptr::{ Pointer, resolve::Resolve };
use serde_json::json;

let mut data = json!({ "foo": { "bar": "baz" } });
let ptr = Pointer::from_static("/foo/bar");
let bar = data.resolve(&ptr).unwrap();
assert_eq!(bar, "baz");

```

#### `ResolveMut::resolve_mut`

```rust
use jsonptr::{Pointer, resolve::ResolveMut};
use serde_json::json;
let parent = ptr.parent().unwrap();
assert_eq!(parent, Pointer::parse("/examples/0").unwrap());

let ptr = Pointer::from_static("/foo/bar");
let mut data = json!({ "foo": { "bar": "baz" }});
let mut bar = data.resolve_mut(&ptr).unwrap();
assert_eq!(bar, "baz");
let (front, remaining) = ptr.split_front().unwrap();
assert_eq!(front.decoded(), "examples");
assert_eq!(remaining, Pointer::parse("/0/name").unwrap());
```

### Assign

#### `Pointer::assign`
Values can be resolved by `Pointer`s using either [`Resolve`] or [`ResolveMut`]
traits. See the [`resolve`] mod for more information.

```rust
use jsonptr::Pointer;
use serde_json::json;

let ptr = Pointer::from_static("/foo/bar");
let mut data = json!({});
let _previous = ptr.assign(&mut data, "qux").unwrap();
assert_eq!(data, json!({"foo": { "bar": "qux" }}))
```

#### `Assign::asign`

```rust
use jsonptr::{assign::Assign, Pointer};
use serde_json::json;

let ptr = Pointer::from_static("/foo/bar");
let mut data = json!({});
let _previous = data.assign(&ptr, "qux").unwrap();
assert_eq!(data, json!({ "foo": { "bar": "qux" }}))
let ptr = Pointer::parse("/foo/bar").unwrap();
let data = json!({"foo": { "bar": 34 }});
let bar = ptr.resolve(&data).unwrap();
assert_eq!(bar, &json!(34));
```

### Delete

#### `Pointer::delete`
Values can be assigned using the [`Assign`] trait. See [`assign`] for more
information.

```rust
use jsonptr::Pointer;
use serde_json::json;

let mut data = json!({ "foo": { "bar": { "baz": "qux" } } });
let ptr = Pointer::from_static("/foo/bar/baz");
assert_eq!(ptr.delete(&mut data), Some("qux".into()));
assert_eq!(data, json!({ "foo": { "bar": {} } }));

// unresolved pointers return None
let mut data = json!({});
assert_eq!(ptr.delete(&mut data), None);
let ptr = Pointer::parse("/secret/universe").unwrap();
let mut data = json!({"secret": { "universe": 42 }});
let replaced = ptr.assign(&mut data, json!(34)).unwrap();
assert_eq!(replaced, Some(json!(42)));
assert_eq!(data, json!({"secret": { "universe": 34 }}));
```

#### `Delete::delete`
Values can be deleted with the [`Delete`] trait. See [`delete`] for more
information.

```rust
use jsonptr::{ Pointer, delete::Delete };
use jsonptr::Pointer;
use serde_json::json;

let mut data = json!({ "foo": { "bar": { "baz": "qux" } } });
let ptr = Pointer::from_static("/foo/bar/baz");
assert_eq!(ptr.delete(&mut data), Some("qux".into()));
assert_eq!(data, json!({ "foo": { "bar": {} } }));

// replacing a root pointer replaces data with `Value::Null`
let ptr = Pointer::root();
let deleted = json!({ "foo": { "bar": {} } });
assert_eq!(data.delete(&ptr), Some(deleted));
assert!(data.is_null());
let ptr = Pointer::parse("/secret/universe").unwrap();
let mut data = json!({"secret": { "universe": 42 }});
let replaced = ptr.assign(&mut data, json!(34)).unwrap();
assert_eq!(replaced, Some(json!(42)));
assert_eq!(data, json!({"secret": { "universe": 34 }}));
```

## Feature Flags

| Flag | Enables |
| :-----: | ----------------------------------------- |
| `"std"` | implements `std::error::Error` for errors |

## Contributions / Issues

Contributions and feedback are always welcome and appreciated.
| Flag | Description | Enables | Default |
| :---------: | ----------------------------------------------------------------------------------------------------------------------------------------- | --------------- | :-----: |
| `"std"` | Implements `std::error::Error` for error types | ||
| `"serde"` | Enables [`serde`] support for types | ||
| `"json"` | Implements ops for [`serde_json::Value`] | `"serde"` ||
| `"toml"` | Implements ops for [`toml::Value`] | `"std"`, `toml` | |
| `"assign"` | Enables the [`assign`] module and related pointer methods, providing a means to assign a value to a specific location within a document | ||
| `"resolve"` | Enables the [`resolve`] module and related pointer methods, providing a means to resolve a value at a specific location within a document | ||
| `"delete"` | Enables the [`delete`] module and related pointer methods, providing a means to delete a value at a specific location within a document | `"resolve"` ||

If you find an issue, please open a ticket or a pull request.
<div class="rustdoc-hidden">

## License

MIT or Apache 2.0.
Licensed under either of

- Apache License, Version 2.0
([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license
([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)

at your convenience.

## Contribution

Contributions and feedback are always welcome and appreciated. If you find an
issue, please open a ticket or a pull request.

Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
dual licensed as above, without any additional terms or conditions.

[LICENSE-APACHE]: LICENSE-APACHE
[LICENSE-MIT]: LICENSE-MIT

</div>

[`Pointer::components`]: (https://docs.rs/jsonptr/latest/jsonptrstruct.Pointer.html#method.components)
[`Pointer::tokens`]: (https://docs.rs/jsonptr/latest/jsonptrstruct.Pointer.html#method.tokens)
[`Pointer`]: https://docs.rs/jsonptr/latest/jsonptr/struct.Pointer.html
[`PointerBuf`]: https://docs.rs/jsonptr/latest/jsonptr/struct.PointerBuf.html
[`Token`]: https://docs.rs/jsonptr/latest/jsonptr/struct.Token.html
[`Tokens`]: https://docs.rs/jsonptr/latest/jsonptr/struct.Tokens.html
[`Components`]: https://docs.rs/jsonptr/latest/jsonptr/struct.Components.html
[`Component`]: https://docs.rs/jsonptr/latest/jsonptr/enum.Component.html
[`Root`]: https://docs.rs/jsonptr/latest/jsonptr/enum.Component.html#variant.Root
[`index`]: https://doc.rust-lang.org/std/primitive.usize.html
[`tokens`]: https://docs.rs/jsonptr/latest/jsonptr/struct.Pointer.html#method.tokens
[`components`]: https://docs.rs/jsonptr/latest/jsonptr/struct.Pointer.html#method.components
[`resolve`]: https://docs.rs/jsonptr/latest/jsonptr/resolve/index.html
[`assign`]: https://docs.rs/jsonptr/latest/jsonptr/assign/index.html
[`delete`]: https://docs.rs/jsonptr/latest/jsonptr/delete/index.html
[`Resolve`]: https://docs.rs/jsonptr/latest/jsonptr/resolve/trait.Resolve.html
[`ResolveMut`]: https://docs.rs/jsonptr/latest/jsonptr/resolve/trait.ResolveMut.html
[`Assign`]: https://docs.rs/jsonptr/latest/jsonptr/assign/trait.Assign.html
[`Delete`]: https://docs.rs/jsonptr/latest/jsonptr/delete/trait.Delete.html
[`serde`]: https://docs.rs/serde/1.0.120/serde/index
[`serde_json`]: https://docs.rs/serde_json/1.0.120/serde_json/enum.Value.html
[`toml`]: https://docs.rs/toml/0.8/toml/enum.Value.html
[`Path`]: https://doc.rust-lang.org/std/path/struct.Path.html
[`PathBuf`]: https://doc.rust-lang.org/std/path/struct.PathBuf.html
Loading

0 comments on commit 89bfee5

Please sign in to comment.