# Shiny JSON Logic — Complete Documentation > A family of JSON Logic libraries for Ruby, PHP and Crystal with 100% spec compliance. > Built by active contributors to the JSON Logic specification. ## Overview Shiny JSON Logic is a family of JSON Logic libraries across multiple languages. JSON Logic allows you to define business rules as portable JSON objects that can be evaluated consistently across different platforms (Ruby, JavaScript, Python, PHP, Crystal, etc.). **Key advantages:** - Store rules in databases - Share rules between frontend and backend - Allow non-programmers to create rules via UI - Version and audit rule changes - Evaluate the same rule across different languages ## Libraries ### Ruby — shiny_json_logic - **Gem**: shiny_json_logic - **RubyGems**: https://rubygems.org/gems/shiny_json_logic - **GitHub**: https://github.com/luismoyano/shiny-json-logic-ruby - **Ruby version**: 2.4+ - **Dependencies**: Zero (stdlib only) - **Spec compliance**: 100% (601/601 tests pass) - **Performance**: Up to 117% faster than other Ruby implementations (benchmark repo: https://github.com/luismoyano/jsonlogic_benchmarks) ### PHP — shiny/json-logic-php - **Package**: shiny/json-logic-php - **Packagist**: https://packagist.org/packages/shiny/json-logic-php - **GitHub**: https://github.com/luismoyano/shiny-json-logic-php - **PHP version**: 8.1+ - **Dependencies**: Zero - **Spec compliance**: 100% (601/601 tests pass) ### Crystal — shiny-json-logic-crystal - **Shard**: shiny-json-logic-crystal - **GitHub**: https://github.com/luismoyano/shiny-json-logic-crystal - **Crystal version**: 1.0+ - **Dependencies**: Zero - **Spec compliance**: 100% (601/601 tests pass) ## Website & Documentation - **Website**: https://shinyjsonlogic.com - **Documentation**: https://shinyjsonlogic.com/docs - **Ruby page**: https://jsonlogicruby.com - **PHP page**: https://shinyjsonlogic.com/php - **Crystal page**: https://shinyjsonlogic.com/crystal - **Specification**: https://shinyjsonlogic.com/specification - **Author**: Luis Moyano - **License**: MIT --- ## Installation ### Ruby ```ruby # Gemfile gem 'shiny_json_logic' ``` ```bash bundle install # or: gem install shiny_json_logic ``` ### PHP ```bash composer require shiny/json-logic-php ``` ### Crystal ```yaml # shard.yml dependencies: shiny-json-logic: github: luismoyano/shiny-json-logic-crystal ``` --- ## Basic Usage ### Ruby ```ruby require 'shiny_json_logic' rule = { ">" => [{ "val" => "age" }, 18] } data = { "age" => 21 } ShinyJsonLogic.apply(rule, data) # => true # Drop-in aliases also work JsonLogic.apply(rule, data) # => true JSONLogic.apply(rule, data) # => true ``` ### PHP ```php use Shiny\JsonLogic\ShinyJsonLogic; $rule = [">" => [["val" => "age"], 18]]; $data = ["age" => 21]; ShinyJsonLogic::apply($rule, $data); // => true ``` ### Crystal ```crystal require "shiny-json-logic" rule = {">" => [{"val" => "age"}, 18]} data = {"age" => 21} ShinyJsonLogic.apply(rule, data) # => true ``` --- ## Why Shiny JSON Logic? ### 1. 100% Spec Compliance Shiny is the only family of JSON Logic libraries that passes all 601 official tests in every supported language. | Gem / Package | Pass Rate | Tests | |---|---|---| | **shiny_json_logic** (Ruby) | **100%** | 601/601 | | **shiny/json-logic-php** (PHP) | **100%** | 601/601 | | **shiny-json-logic-crystal** (Crystal) | **100%** | 601/601 | | json-logic-rb (Ruby) | 93.68% | 563/601 | | json_logic (Ruby) | 63.73% | 383/601 | | jwadhams/json-logic-php (PHP) | 63.9% | ~384/601 | ### 2. Correct Truthiness JSON Logic follows JavaScript truthiness rules. Most libraries get `{}` (empty object) wrong. **Falsy values per spec**: `false`, `null`, `0`, `""`, `[]`, `{}` ```ruby rule = { "if" => [{ "var" => "filters" }, "has filters", "no filters"] } data = { "filters" => {} } # Other libraries: "has filters" (WRONG — {} treated as truthy) # shiny_json_logic: "no filters" (CORRECT — {} is falsy per spec) ``` This is documented in the official ACCEPTED_PROPOSALS: https://github.com/json-logic/.github/blob/main/ACCEPTED_PROPOSALS.md ### 3. Performance (Ruby) shiny_json_logic is up to 117% faster than other Ruby implementations. Full benchmark data: https://github.com/luismoyano/jsonlogic_benchmarks | Mode | shiny_json_logic | json-logic-rb | Difference | |---|---|---|---| | All tests | **67,523 ops/s** | 45,217 ops/s | **+49%** | | Fair (563 common tests) | **48,981 ops/s** | 46,883 ops/s | **+4.5%** | PHP benchmarks vs jwadhams/json-logic-php are not yet available. ### 4. Extended Operators Operators not available in other implementations: - `val` — like `var` but with array notation and scope navigation in iterators (recommended over `var`) - `exists` — check if a path exists in data without returning its value - `??` — null coalescing: returns left side unless null, then right side - `try` / `throw` — structured error handling within rules ### 5. Drop-in Replacement #### Ruby ```ruby # shiny_json_logic registers these aliases automatically ShinyJsonLogic.apply(rule, data) JsonLogic.apply(rule, data) # alias JSONLogic.apply(rule, data) # alias ``` #### PHP ```php // shiny/json-logic-php registers global aliases automatically ShinyJsonLogic::apply($rule, $data); JsonLogic::apply($rule, $data); // alias JSONLogic::apply($rule, $data); // alias ``` --- ## Supported Operators ### Logic - `if` / `?:` — conditional (if-then-else) - `==` — equality with type coercion - `===` — strict equality - `!=` — inequality - `!==` — strict inequality - `!` — negation - `!!` — double negation (truthy check) - `and` — logical AND (short-circuit) - `or` — logical OR (short-circuit) - `??` — null coalescing *(Shiny exclusive)* ### Control Flow - `try` — catch errors within a rule *(Shiny exclusive)* - `throw` — throw a named error *(Shiny exclusive)* ### Comparison - `>`, `>=`, `<`, `<=` — numeric comparisons (`<` and `<=` support between: `{"<": [1, {"var": "x"}, 10]}`) ### Arithmetic - `+` — addition - `-` — subtraction - `*` — multiplication - `/` — division - `%` — modulo - `min`, `max` — minimum / maximum ### String - `cat` — concatenation - `substr` — substring - `in` — string contains ### Array - `in` — array contains - `merge` — merge arrays - `map` — transform elements - `filter` — filter elements - `reduce` — reduce to single value - `all` — all elements match - `some` — any element matches - `none` — no elements match ### Data Access - `var` — access data by path (dot notation, default values) - `val` — like `var` with scope navigation *(Shiny exclusive, recommended)* - `exists` — check if path exists *(Shiny exclusive)* - `missing` — list missing keys - `missing_some` — check if some keys are missing --- ## PHP: {} vs [] caveat In PHP, `json_decode` with the `assoc` flag (default) converts both `{}` and `[]` to an empty PHP array, making them indistinguishable. This means `{"+" : {}}` returns `0` instead of `NaN`. To get fully accurate behaviour, use `json_decode($json)` without `true` so PHP preserves `stdClass` objects. The engine handles both modes; the difference only surfaces in this edge case. --- ## Advanced Examples ### Feature Flags (Ruby) ```ruby rule = { "or" => [ { "in" => [{ "val" => "user.email" }, ["beta@example.com", "tester@example.com"]] }, { "and" => [ { "==" => [{ "val" => "user.plan" }, "enterprise"] }, { ">=" => [{ "val" => "user.created_at" }, "2025-01-01"] } ]} ] } data = { "user" => { "email" => "regular@example.com", "plan" => "enterprise", "created_at" => "2025-06-15" } } ShinyJsonLogic.apply(rule, data) # => true ``` ### Pricing Rules (Ruby) ```ruby rule = { "if" => [ { ">=" => [{ "val" => "cart.total" }, 100] }, { "*" => [{ "val" => "cart.total" }, 0.9] }, # 10% discount { "val" => "cart.total" } # no discount ] } ShinyJsonLogic.apply(rule, { "cart" => { "total" => 150 } }) # => 135.0 ``` ### Scope Navigation with val (Ruby) ```ruby # Access parent scope from inside a map/filter rule = { "filter" => [ { "val" => "products" }, { ">" => [{ "val" => ".price" }, { "val" => ["min_price", 1] }] } ] } ``` ### Access Control (PHP) ```php $rule = [ "and" => [ ["in" => [["val" => "user.role"], ["admin", "moderator"]]], ["==" => [["val" => "resource.owner_id"], ["val" => "user.id"]]] ] ]; $data = [ "user" => ["id" => 123, "role" => "moderator"], "resource" => ["owner_id" => 123] ]; ShinyJsonLogic::apply($rule, $data); // => true ``` --- ## Error Handling (Ruby) ```ruby begin result = ShinyJsonLogic.apply(rule, data) rescue ShinyJsonLogic::Error => e puts "Rule error: #{e.message}" end ``` --- ## Migration ### Ruby: from json-logic-rb or json_logic Change your Gemfile: ```ruby gem 'shiny_json_logic' ``` No code changes needed — `JsonLogic.apply` and `JSONLogic.apply` are registered as aliases automatically. ### PHP: from jwadhams/json-logic-php Change your composer.json: ```bash composer require shiny/json-logic-php ``` Then update your `use` statement: ```php // Before use JWadhams\JsonLogic; // After use Shiny\JsonLogic\ShinyJsonLogic; // or use the global alias — no use statement needed: JsonLogic::apply($rule, $data); ``` --- ## Links - **Website**: https://shinyjsonlogic.com - **Documentation**: https://shinyjsonlogic.com/docs - **Specification**: https://shinyjsonlogic.com/specification - **Ruby gem**: https://rubygems.org/gems/shiny_json_logic - **PHP package**: https://packagist.org/packages/shiny/json-logic-php - **Ruby GitHub**: https://github.com/luismoyano/shiny-json-logic-ruby - **PHP GitHub**: https://github.com/luismoyano/shiny-json-logic-php - **Crystal GitHub**: https://github.com/luismoyano/shiny-json-logic-crystal - **Benchmark repo**: https://github.com/luismoyano/jsonlogic_benchmarks - **JSON Logic spec**: https://jsonlogic.com - **Author**: Luis Moyano (https://github.com/luismoyano) --- ## License MIT — free for commercial and personal use.