shiny-json-logic-crystal

A modern JSONLogic runtime for Crystal that actually works

shiny_json_logic ✨

Shards Crystal License: MIT GitHub Clones

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: JsonLogic and JSONLogic available 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 rule
  • ShinyJsonLogic::Errors::InvalidArguments — invalid arguments to operator
  • ShinyJsonLogic::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


License

MIT License.

Use it. Fork it. Ship it. (:


Shine bright like a 🔮

Repository

shiny-json-logic-crystal

Owner
Statistic
  • 0
  • 0
  • 0
  • 0
  • 0
  • 3 months ago
  • April 18, 2026
License

MIT License

Links
Synced at

Sat, 18 Apr 2026 11:16:30 GMT

Languages