Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/jg-rp/ruby-json-p3
JSONPath, JSON Patch and JSON Pointer for Ruby
https://github.com/jg-rp/ruby-json-p3
json jsonpath ruby
Last synced: 2 months ago
JSON representation
JSONPath, JSON Patch and JSON Pointer for Ruby
- Host: GitHub
- URL: https://github.com/jg-rp/ruby-json-p3
- Owner: jg-rp
- License: mit
- Created: 2024-10-14T10:15:43.000Z (3 months ago)
- Default Branch: main
- Last Pushed: 2024-10-26T15:08:58.000Z (3 months ago)
- Last Synced: 2024-11-04T09:46:45.065Z (3 months ago)
- Topics: json, jsonpath, ruby
- Language: Ruby
- Homepage:
- Size: 171 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
Awesome Lists containing this project
README
JSONPath, JSON Patch and JSON Pointer for Ruby
We follow RFC 9535 strictly and test against the JSONPath Compliance Test Suite.---
**Table of Contents**
- [Install](#install)
- [Example](#example)
- [Links](#links)
- [Related projects](#related-projects)
- [Quick start](#quick-start)
- [Contributing](#contributing)## Install
Add `'json_p3'` to your Gemfile:
```
gem 'json_p3', '~> 0.2.1'
```Or
```
gem install json_p3
```### Checksum
JSON P3 is cryptographically signed. To be sure the gem you install hasn’t been tampered with, add my public key (if you haven’t already) as a trusted certificate:
```
gem cert --add <(curl -Ls https://raw.githubusercontent.com/jg-rp/ruby-json-p3/refs/heads/main/certs/jgrp.pem)
```Followed by:
```
gem install json_p3 -P MediumSecurity
```JSON P3 has no runtime dependencies, so `-P HighSecurity` is OK too. See https://guides.rubygems.org/security/ for mor information.
## Example
```ruby
require "json_p3"
require "json"data = JSON.parse <<~JSON
{
"users": [
{
"name": "Sue",
"score": 100
},
{
"name": "Sally",
"score": 84,
"admin": false
},
{
"name": "John",
"score": 86,
"admin": true
},
{
"name": "Jane",
"score": 55
}
],
"moderator": "John"
}
JSONJSONP3.find("$.users[[email protected] > 85]", data).each do |node|
puts node.value
end# {"name"=>"Sue", "score"=>100}
# {"name"=>"John", "score"=>86, "admin"=>true}
```Or, reading JSON data from a file:
```ruby
require "json_p3"
require "json"data = JSON.load_file("/path/to/some.json")
JSONP3.find("$.some.query", data).each do |node|
puts node.value
end
```You could read data from a YAML formatted file too, or any data format that can be loaded into hashes and arrays.
```ruby
require "json_p3"
require "yaml"data = YAML.load_file("/tmp/some.yaml")
JSONP3.find("$.users[[email protected] > 85]", data).each do |node|
puts node.value
end
```## Links
- Change log: https://github.com/jg-rp/ruby-json-p3/blob/main/CHANGELOG.md
- RubyGems: https://rubygems.org/gems/json_p3
- Source code: https://github.com/jg-rp/ruby-json-p3
- Issue tracker: https://github.com/jg-rp/ruby-json-p3/issues## Related projects
- [Python JSONPath RFC 9535](https://github.com/jg-rp/python-jsonpath-rfc9535) - A Python implementation of JSONPath that follows RFC 9535 strictly.
- [Python JSONPath](https://github.com/jg-rp/python-jsonpath) - Another Python package implementing JSONPath, but with additional features and customization options.
- [JSON P3](https://github.com/jg-rp/json-p3) - RFC 9535 implemented in TypeScript.## Quick start
### find
`find(query, value) -> Array[JSONPathNode]`
Apply JSONPath expression _query_ to JSON-like data _value_. An array of JSONPathNode instances is returned, one node for each value matched by _query_. The returned array will be empty if there were no matches.
Each `JSONPathNode` has:
- a `value` attribute, which is the JSON-like value associated with the node.
- a `location` attribute, which is a nested array of hash/object names and array indices that were required to reach the node's value in the target JSON document.
- a `path()` method, which returns the normalized path to the node in the target JSON document.```ruby
require "json_p3"
require "json"data = JSON.parse <<~JSON
{
"users": [
{
"name": "Sue",
"score": 100
},
{
"name": "Sally",
"score": 84,
"admin": false
},
{
"name": "John",
"score": 86,
"admin": true
},
{
"name": "Jane",
"score": 55
}
],
"moderator": "John"
}
JSONJSONP3.find("$.users[[email protected] > 85]", data).each do |node|
puts "#{node.value} at #{node.path}"
end# {"name"=>"Sue", "score"=>100} at $['users'][0]
# {"name"=>"John", "score"=>86, "admin"=>true} at $['users'][2]
```### compile
`compile(query) -> JSONPath`
Prepare a JSONPath expression for repeated application to different JSON-like data. An instance of `JSONPath` has a `find(data)` method, which behaves similarly to the module-level `find(query, data)` method.
```ruby
require "json_p3"
require "json"data = JSON.parse <<~JSON
{
"users": [
{
"name": "Sue",
"score": 100
},
{
"name": "Sally",
"score": 84,
"admin": false
},
{
"name": "John",
"score": 86,
"admin": true
},
{
"name": "Jane",
"score": 55
}
],
"moderator": "John"
}
JSONpath = JSONP3.compile("$.users[[email protected] > 85]")
path.find(data).each do |node|
puts "#{node.value} at #{node.path}"
end# {"name"=>"Sue", "score"=>100} at $['users'][0]
# {"name"=>"John", "score"=>86, "admin"=>true} at $['users'][2]
```### JSONPathEnvironment
The `find` and `compile` methods described above are convenience methods equivalent to
```
JSONP3::DEFAULT_ENVIRONMENT.find(query, data)
```and
```
JSONP3::DEFAULT_ENVIRONMENT.compile(query)
```You could create your own environment like this:
```ruby
require "json_p3"jsonpath = JSONP3::JSONPathEnvironment.new
nodes = jsonpath.find("$.*", { "a" => "b", "c" => "d" })
pp nodes.map(&:value) # ["b", "d"]
```To configure an environment with custom filter functions or non-standard selectors, inherit from `JSONPathEnvironment` and override some of its constants or the `#setup_function_extensions` method.
```ruby
class MyJSONPathEnvironment < JSONP3::JSONPathEnvironment
# The maximum integer allowed when selecting array items by index.
MAX_INT_INDEX = (2**53) - 1# The minimum integer allowed when selecting array items by index.
MIN_INT_INDEX = -(2**53) + 1# The maximum number of arrays and hashes the recursive descent segment will
# traverse before raising a {JSONPathRecursionError}.
MAX_RECURSION_DEPTH = 100# One of the available implementations of the _name selector_.
#
# - {NameSelector} (the default) will select values from hashes using string keys.
# - {SymbolNameSelector} will select values from hashes using string or symbol keys.
#
# Implement your own name selector by inheriting from {NameSelector} and overriding
# `#resolve`.
NAME_SELECTOR = NameSelector# An implementation of the _index selector_. The default implementation will
# select values from arrays only. Implement your own by inheriting from
# {IndexSelector} and overriding `#resolve`.
INDEX_SELECTOR = IndexSelector# Override this function to configure JSONPath function extensions.
# By default, only the standard functions described in RFC 9535 are enabled.
def setup_function_extensions
@function_extensions["length"] = Length.new
@function_extensions["count"] = Count.new
@function_extensions["value"] = Value.new
@function_extensions["match"] = Match.new
@function_extensions["search"] = Search.new
end
```### JSONPathError
`JSONPathError` is the base class for all JSONPath exceptions. The following classes inherit from `JSONPathError` and will only occur when parsing a JSONPath expression, not when applying a path to some data.
- `JSONPathSyntaxError`
- `JSONPathTypeError`
- `JSONPathNameError``JSONPathError` implements `#detailed_message`. With recent versions of Ruby you should get useful error messages.
```
JSONP3::JSONPathSyntaxError: unexpected trailing whitespace
-> '$.foo ' 1:5
|
1 | $.foo
| ^ unexpected trailing whitespace
```## Contributing
Your contributions and questions are always welcome. Feel free to ask questions, report bugs or request features on the [issue tracker](https://github.com/jg-rp/ruby-json-p3/issues) or on [Github Discussions](https://github.com/jg-rp/ruby-json-p3/discussions). Pull requests are welcome too.
### Development
The [JSONPath Compliance Test Suite](https://github.com/jsonpath-standard/jsonpath-compliance-test-suite) is included as a git [submodule](https://git-scm.com/book/en/v2/Git-Tools-Submodules). Clone the JSON P3 git repository and initialize the CTS submodule.
```shell
$ git clone [email protected]:jg-rp/ruby-json-p3.git
$ cd ruby-json-p3
$ git submodule update --init
```We use [Bundler](https://bundler.io/) and [Rake](https://ruby.github.io/rake/). Install development dependencies with:
```
bundle install
```Run tests with:
```
bundle exec rake test
```Lint with:
```
bundle exec rubocop
```And type check with:
```
bundle exec steep
```Run one of the benchmarks with:
```
bundle exec ruby performance/benchmark_ips.rb
```### Profiling
#### CPU profile
Dump profile data with `bundle exec ruby performance/profile.rb`, then generate an HTML flame graph with:
```
bundle exec stackprof --d3-flamegraph .stackprof-cpu-just-compile.dump > flamegraph-cpu-just-compile.html
```#### Memory profile
Print memory usage to the terminal.
```
bundle exec ruby performance/memory_profile.rb
```### TruffleRuby
On macOS Sonoma using MacPorts and `rbenv`, `LIBYAML_PREFIX=/opt/local/lib` is needed to install TruffleRuby and when executing any `bundle` command.