shiny-json-logic-crystal
shiny_json_logic ✨
shiny_json_logic is a pure Crystal, zero-dependency JSON Logic implementation passing all the specification tests.
This is the Crystal port of shiny_json_logic.
Why shiny_json_logic?
- ✅ 100% spec-compliant passes all 601 official JSON Logic tests.
- 🧩 Zero runtime dependencies stdlib only. Just add the shard.
- ⚡ Native Crystal performance compiled, type-safe, fast.
- 🔁 Drop-in aliases:
JsonLogicandJSONLogicavailable out of the box. - 🔧 Actively maintained and aligned with the evolving JSON Logic specification.
Installation
Add to your shard.yml:
dependencies:
shiny_json_logic:
github: luismoyano/shiny-json-logic-crystal
Then run:
shards install
Usage
require "shiny_json_logic"
# Basic evaluation
ShinyJsonLogic.apply(JSON.parse(%({"==" : [1, 1]})))
# => true
# With data
rule = JSON.parse(%({"var" : "name"}))
data = JSON.parse(%({"name" : "Luis"}))
ShinyJsonLogic.apply(rule, data)
# => "Luis"
# Feature flag example
rule = JSON.parse(%({"==" : [{"var": "plan"}, "premium"]}))
data = JSON.parse(%({"plan": "premium"}))
ShinyJsonLogic.apply(rule, data)
# => true
Nested logic
Rules can be nested arbitrarily:
rule = JSON.parse(%(
{"if": [{"var": "financing"}, {"missing": ["apr"]}, []]}
))
data = JSON.parse(%({"financing": true}))
ShinyJsonLogic.apply(rule, data)
# => ["apr"]
Drop-in aliases
JsonLogic and JSONLogic are available as aliases:
JsonLogic.apply(JSON.parse(%({">" : [{"var": "score"}, 90]})), JSON.parse(%({"score": 95})))
# => true
Supported operators
| Category | Operators |
|---|---|
| Data access | var, missing, missing_some, exists, val |
| Logic | if, ?:, and, or, !, !! |
| Comparison | ==, ===, !=, !==, >, >=, <, <= |
| Arithmetic | +, -, *, /, %, max, min |
| String | cat, substr |
| Array | map, filter, reduce, all, none, some, merge, in |
| Coalesce | ?? |
| Error handling | throw, try |
| Utility | preserve |
Error handling
shiny_json_logic uses native Crystal exceptions:
# Unknown operators raise an error
ShinyJsonLogic.apply(JSON.parse(%({"unknown_op": [1, 2]})))
# => raises ShinyJsonLogic::Errors::UnknownOperator
# You can use try/throw for controlled error handling within rules
rule = JSON.parse(%(
{"try": [{"throw": "Something went wrong"}, {"cat": ["Error: ", {"var": "type"}]}]}
))
ShinyJsonLogic.apply(rule, JSON.parse("null"))
# => "Error: Something went wrong"
Exception classes:
ShinyJsonLogic::Errors::UnknownOperator— unknown operator in ruleShinyJsonLogic::Errors::InvalidArguments— invalid arguments to operatorShinyJsonLogic::Errors::NotANumber— NaN result in numeric operation
Or rescue ShinyJsonLogic::Errors::Base to handle all library errors in one sweep.
Compatibility
Tested against the official JSON Logic test suite (601 tests).
| Passed | Total |
|---|---|
| 601 | 601 |
Development
shards install
crystal spec
To run the official test suite against live test data:
bin/test.sh
Requires curl and crystal. Fetches the official tests at runtime from github.com/json-logic/.github.
Contributing
Contributions are welcome — especially:
- spec alignment improvements
- missing operators
- edge-case tests
- performance improvements
Please include tests with any change.
See CONTRIBUTING.md for details.
Repository: https://github.com/luismoyano/shiny-json-logic-crystal
Related projects
- shiny_json_logic (Ruby): 601/601 official tests, the fastest & most compliant Ruby implementation
- shiny/json-logic-php — 601/601 official tests, the most compliant PHP implementation
- shinyjsonlogic.com — JSON Logic playground, docs, and specification reference
License
MIT License.
Use it. Fork it. Ship it. (:
Shine bright like a 🔮
shiny-json-logic-crystal
- 0
- 0
- 0
- 0
- 0
- 3 months ago
- April 18, 2026
MIT License
Sat, 18 Apr 2026 11:16:30 GMT