json-logic-rb 0.2.0.beta1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +76 -116
- data/lib/json_logic/operations/missing.rb +2 -0
- data/lib/json_logic/operations/strict_equal.rb +13 -5
- data/lib/json_logic/operations/strict_not_equal.rb +13 -5
- data/lib/json_logic/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bf7e4291a1fe0a56b1387ca35f03d239679f4d0c76333a3d0d0f3933efeead0b
|
|
4
|
+
data.tar.gz: 134bb254ff81c389daa1d9527b9496d17d0417316143586ea8ade75c739f2657
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2a98a01a255cdce55c19940171b00fcf652e9735369e6316d747cbfc70108ed42c207d8beca244bf042b47f0a7aa978b962e523fed9662bc2d35970f5476d6b4
|
|
7
|
+
data.tar.gz: f2a6bedd19099407dbd4398647553cbe9a341926b71b0cdd6c50f99fbe856015ff20a8408087e295c4a459dd13d2c2cdf360810b9af4ceff07e98e102e8012da
|
data/README.md
CHANGED
|
@@ -1,37 +1,24 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
[![jsonlogic core][src-core]](https://jsonlogic.com/tests.json) [![jsonlogic community][src-community]](https://github.com/json-logic/compat-tables/tree/main/suites) [](https://github.com/tavrelkate/json-logic-rb/actions/workflows/compliance.yml?query=branch%3Amain) <a href="https://rubygems.org/gems/json-logic-rb"><img alt="rubygems" src="https://img.shields.io/gem/v/json-logic-rb"></a> <a href="LICENSE"><img alt="license" src="https://img.shields.io/badge/license-MIT-informational"></a>
|
|
12
2
|
|
|
13
3
|
# json-logic-rb
|
|
14
4
|
|
|
15
|
-
Ruby implementation of [JsonLogic](https://jsonlogic.com/)
|
|
16
|
-
|
|
17
|
-
[![jsonlogic core][src-core]](https://jsonlogic.com/tests.json) [![jsonlogic community][src-community]](https://github.com/json-logic/compat-tables/tree/main/suites) [](https://github.com/tavrelkate/json-logic-rb/actions/workflows/compliance.yml?query=branch%3Amain) <a href="https://rubygems.org/gems/json-logic-rb"><img alt="rubygems" src="https://img.shields.io/gem/v/json-logic-rb"></a> <a href="LICENSE"><img alt="license" src="https://img.shields.io/badge/license-MIT-informational"></a>
|
|
5
|
+
Ruby implementation of [JsonLogic](https://jsonlogic.com/). Pure and extensible. Full compliance with both core and community-extended specifications.
|
|
18
6
|
|
|
19
7
|
## Table of Contents
|
|
20
8
|
- [What](#what)
|
|
21
9
|
- [Install](#install)
|
|
22
10
|
- [Quick start](#quick-start)
|
|
23
|
-
- [
|
|
24
|
-
|
|
25
|
-
- [2. Lazy Operations](#2-lazy-operations)
|
|
26
|
-
- [Why laziness matters?](#why-laziness-matters)
|
|
27
|
-
- [Compliance and tests](#compliance-and-tests)
|
|
28
|
-
- [Script](#script)
|
|
29
|
-
- [Supported Operations (Built‑in)](#supported-operations-built-in)
|
|
11
|
+
- [Complience](#complience)
|
|
12
|
+
- [Supported Operations (Built-in)](#supported-operations-built-in)
|
|
30
13
|
- [Adding Operations](#adding-operations)
|
|
31
14
|
- [Enable JsonLogic Semantics (optional)](#enable-jsonlogic-semantics-optional)
|
|
32
15
|
- [Parameters](#parameters)
|
|
33
16
|
- [Proc / Lambda](#proc--lambda)
|
|
34
17
|
- [Class](#class)
|
|
18
|
+
- [Laziness](#laziness)
|
|
19
|
+
- [1. Default Operations](#1-default-operations)
|
|
20
|
+
- [2. Lazy Operations](#2-lazy-operations)
|
|
21
|
+
- [Why laziness matters?](#why-laziness-matters)
|
|
35
22
|
- [JsonLogic Semantic](#jsonlogic-semantic)
|
|
36
23
|
- [Comparisons](#comparisons)
|
|
37
24
|
- [Truthiness](#truthiness)
|
|
@@ -84,106 +71,22 @@ JsonLogic.apply(rule, data)
|
|
|
84
71
|
# => 42
|
|
85
72
|
```
|
|
86
73
|
|
|
87
|
-
## How
|
|
88
74
|
|
|
89
|
-
There are two types of operations: [Default Operations](#1-default-operations) and [Lazy Operations](#2-lazy-operations).
|
|
90
|
-
|
|
91
|
-
### 1. Default Operations
|
|
92
|
-
|
|
93
|
-
For **Default Operations**, the it evaluates all arguments first and then calls the operator with the resulting Ruby values.
|
|
94
|
-
This matches the reference behavior for arithmetic, comparisons, string operations, and other pure operations that do not control evaluation order.
|
|
95
|
-
|
|
96
|
-
**Groups and references:**
|
|
97
|
-
|
|
98
|
-
- [Numeric operations](https://jsonlogic.com/operations.html#numeric-operations)
|
|
99
|
-
- [String operations](https://jsonlogic.com/operations.html#string-operations)
|
|
100
|
-
- [Array operations](https://jsonlogic.com/operations.html#array-operations) — simple transform like `merge`.
|
|
101
75
|
|
|
102
|
-
### 2. Lazy Operations
|
|
103
76
|
|
|
104
|
-
Some operations must control whether and when their arguments are evaluated. They implement branching, short-circuiting, or “apply a rule per item” semantics. For these **Lazy Operations**, the engine passes raw sub-rules and data. The operator then evaluates only the sub-rules it actually needs.
|
|
105
77
|
|
|
106
|
-
|
|
78
|
+
## Complience
|
|
107
79
|
|
|
108
|
-
|
|
109
|
-
- [
|
|
110
|
-
- [
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
**Example #1**
|
|
114
|
-
|
|
115
|
-
```ruby
|
|
116
|
-
# filter: keep numbers >= 2
|
|
117
|
-
JsonLogic.apply(
|
|
118
|
-
{ "filter" => [ { "var" => "ints" }, { ">=" => [ { "var" => "" }, 2 ] } ] },
|
|
119
|
-
{ "ints" => [1,2,3] }
|
|
120
|
-
)
|
|
121
|
-
# => [2, 3]
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
### Why laziness matters?
|
|
125
|
-
|
|
126
|
-
Lazy operations prevent evaluation of branches you do not need.
|
|
127
|
-
|
|
128
|
-
If hypothetically division by zero raises an error, lazy control would avoid it.
|
|
129
|
-
```ruby
|
|
130
|
-
JsonLogic.apply({ "or" => [1, { "/" => [1, 0] }] })
|
|
131
|
-
# => 1
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
> In this gem division returns nil on divide‑by‑zero, but this example show why lazy evaluation is required by the spec: branching and boolean operators must not evaluate unused branches.
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
## Compliance and tests
|
|
142
|
-
|
|
143
|
-
The JsonLogic specification provides test suites — concrete inputs with expected outputs that validate the implementation of operations. The specification come in two variants:
|
|
144
|
-
- [![jsonlogic core][src-core]](https://jsonlogic.com/tests.json) — [original JsonLogic website](https://jsonlogic.com/tests.json);
|
|
145
|
-
- [![jsonlogic community][src-community]](https://github.com/json-logic/compat-tables/tree/main/suites) — [extensions built on top of the core](https://github.com/json-logic/compat-tables/tree/main/suites);
|
|
80
|
+
The JsonLogic specification provides test suites — concrete inputs with expected outputs that validate the implementation of operations. The specification comes in two variants:
|
|
81
|
+
- [![jsonlogic core][src-core]](https://jsonlogic.com/tests.json) – [original JsonLogic website](https://jsonlogic.com/tests.json)
|
|
82
|
+
- [![jsonlogic community][src-community]](https://github.com/json-logic/compat-tables/tree/main/suites) – [extensions built on top of the core](https://github.com/json-logic/compat-tables/tree/main/suites)
|
|
146
83
|
|
|
147
84
|
The "extra" exists because "core" hasn't changed in years — and that’s fine, "core" is a solid, finished foundation. Think of it as v1, while "extra" is the v2+ evolution as there are no visible plans to change the original.
|
|
148
85
|
|
|
149
|
-
### Script
|
|
150
86
|
|
|
151
|
-
|
|
87
|
+
## Supported Operations (Built-in)
|
|
152
88
|
|
|
153
|
-
```bash
|
|
154
|
-
mkdir -p spec/tmp/v1
|
|
155
|
-
curl -L https://jsonlogic.com/tests.json -o spec/tmp/v1/tests.json
|
|
156
|
-
```
|
|
157
89
|
|
|
158
|
-
Download test suite v2:
|
|
159
|
-
|
|
160
|
-
```bash
|
|
161
|
-
mkdir -p spec/tmp/v2
|
|
162
|
-
git clone https://github.com/json-logic/compat-tables.git /tmp/compat-tables
|
|
163
|
-
ruby script/build_tests_json.rb /tmp/compat-tables/suites spec/tmp/v2/tests.json
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
Run by version:
|
|
167
|
-
|
|
168
|
-
```bash
|
|
169
|
-
ruby script/compliance.rb -v 1
|
|
170
|
-
ruby script/compliance.rb -v 2
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
Run by file path:
|
|
174
|
-
|
|
175
|
-
```bash
|
|
176
|
-
ruby script/compliance.rb -f spec/tmp/v2/tests.json
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
## Supported Operations (Built‑in)
|
|
181
|
-
|
|
182
|
-
Don’t expect JsonLogic to include every specialized operation. It’s intentionally small and not a programming language. It will never do everything.
|
|
183
|
-
|
|
184
|
-
You can add custom operations yourself — check out [§Adding Operations](https://www.google.com/search?q=%23adding-operations)— or consider if the logic can be expressed with what’s already there.
|
|
185
|
-
|
|
186
|
-
If a feature is simple, lightweight, and universally needed — open an issue or discussion.
|
|
187
90
|
|
|
188
91
|
|
|
189
92
|
| Operator | Supported | Source |
|
|
@@ -236,19 +139,23 @@ If a feature is simple, lightweight, and universally needed — open an issue or
|
|
|
236
139
|
| `throw` | ✅ |  |
|
|
237
140
|
| `preserve` | ✅ |  |
|
|
238
141
|
| Docs-only / Not implemented | | |
|
|
239
|
-
| `log` | 🚫 |  |
|
|
240
143
|
|
|
241
144
|
|
|
242
145
|
[src-core]: https://img.shields.io/badge/jsonlogic-core-2ea44f?style=flat-square
|
|
243
146
|
[src-community]: https://img.shields.io/badge/jsonlogic--community-extra-0366d6?style=flat-square
|
|
244
147
|
|
|
148
|
+
|
|
245
149
|
## Adding Operations
|
|
246
150
|
|
|
247
|
-
|
|
151
|
+
Don’t expect JsonLogic to include every specialized operation. It’s intentionally small and not a programming language. It will never do everything.
|
|
152
|
+
|
|
153
|
+
Before you reach for a custom solution, see if you can express your logic using the [§Supported Operations (Built‑in)](https://www.google.com/search?q=%23supported-operations-built-in). Often, a simple change in perspective is all you need to get the job done with what's already there.
|
|
248
154
|
|
|
155
|
+
If that doesn't cut it, adding a custom operation is straightforward. Keep it simple: start with a Proc or a Lambda. If needed – promote it to a Class.
|
|
249
156
|
|
|
250
157
|
|
|
251
|
-
###
|
|
158
|
+
### Enable JsonLogic Semantics (optional)
|
|
252
159
|
Enable semantics to mirror JsonLogic’s comparison and truthiness in Ruby.
|
|
253
160
|
|
|
254
161
|
See [§JsonLogic Semantic](#jsonlogic-semantic) for details.
|
|
@@ -286,7 +193,7 @@ JsonLogic.add_operation("starts_with", lazy: true) do |(string_rule, prefix_rule
|
|
|
286
193
|
end
|
|
287
194
|
```
|
|
288
195
|
|
|
289
|
-
See [§
|
|
196
|
+
See [§Laziness](#laziness) for details.
|
|
290
197
|
|
|
291
198
|
Use immediately:
|
|
292
199
|
|
|
@@ -329,6 +236,59 @@ JsonLogic.apply({ "starts_with" => [ { "var" => "email" }, "admin@" ] })
|
|
|
329
236
|
|
|
330
237
|
|
|
331
238
|
|
|
239
|
+
|
|
240
|
+
## Laziness
|
|
241
|
+
|
|
242
|
+
There are two types of operations: [Default Operations](#1-default-operations) and [Lazy Operations](#2-lazy-operations).
|
|
243
|
+
|
|
244
|
+
### 1. Default Operations
|
|
245
|
+
|
|
246
|
+
For **Default Operations**, the it evaluates all arguments first and then calls the operator with the resulting Ruby values.
|
|
247
|
+
This matches the reference behavior for arithmetic, comparisons, string operations, and other pure operations that do not control evaluation order.
|
|
248
|
+
|
|
249
|
+
**Groups and references:**
|
|
250
|
+
|
|
251
|
+
- [Numeric operations](https://jsonlogic.com/operations.html#numeric-operations)
|
|
252
|
+
- [String operations](https://jsonlogic.com/operations.html#string-operations)
|
|
253
|
+
- [Array operations](https://jsonlogic.com/operations.html#array-operations) — simple transform like `merge`.
|
|
254
|
+
|
|
255
|
+
### 2. Lazy Operations
|
|
256
|
+
|
|
257
|
+
Some operations must control whether and when their arguments are evaluated. They implement branching, short-circuiting, or “apply a rule per item” semantics. For these **Lazy Operations**, the engine passes raw sub-rules and data. The operator then evaluates only the sub-rules it actually needs.
|
|
258
|
+
|
|
259
|
+
**Groups and references:**
|
|
260
|
+
|
|
261
|
+
- [Logic and Boolean Operations](https://jsonlogic.com/operations.html#logic-and-boolean-operations) — short-circuit/branching like `or`.
|
|
262
|
+
- [Comparison operations](https://jsonlogic.com/operations.html#logic-and-boolean-operations) — equality/ordering like `==`.
|
|
263
|
+
- [Array operations](https://jsonlogic.com/operations.html#array-operations) — enumerable evaluation like `map`.
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
**Example #1**
|
|
267
|
+
|
|
268
|
+
```ruby
|
|
269
|
+
# filter: keep numbers >= 2
|
|
270
|
+
JsonLogic.apply(
|
|
271
|
+
{ "filter" => [ { "var" => "ints" }, { ">=" => [ { "var" => "" }, 2 ] } ] },
|
|
272
|
+
{ "ints" => [1,2,3] }
|
|
273
|
+
)
|
|
274
|
+
# => [2, 3]
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### Why laziness matters?
|
|
278
|
+
|
|
279
|
+
Lazy operations prevent evaluation of branches you do not need.
|
|
280
|
+
|
|
281
|
+
If hypothetically division by zero raises an error, lazy control would avoid it.
|
|
282
|
+
```ruby
|
|
283
|
+
JsonLogic.apply({ "or" => [1, { "/" => [1, 0] }] })
|
|
284
|
+
# => 1
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
> In this gem division returns nil on divide‑by‑zero, but this example show why lazy evaluation is required by the spec: branching and boolean operators must not evaluate unused branches.
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
|
|
332
292
|
## JsonLogic Semantic
|
|
333
293
|
|
|
334
294
|
All supported Operations follow JsonLogic semantics.
|
|
@@ -391,7 +351,7 @@ using JsonLogic::Semantics
|
|
|
391
351
|
|
|
392
352
|
MIT — see [LICENSE](LICENSE).
|
|
393
353
|
|
|
394
|
-
##
|
|
354
|
+
## Maintainers
|
|
395
355
|
|
|
396
|
-
- [Valeriya Petrova](https://github.com/piatrova
|
|
356
|
+
- [Valeriya Petrova](https://github.com/valeryia-piatrova)
|
|
397
357
|
- [Tavrel Kate](https://github.com/tavrelkate)
|
|
@@ -11,14 +11,22 @@ class JsonLogic::Operations::StrictEqual < JsonLogic::LazyOperation
|
|
|
11
11
|
prev = JsonLogic.apply(args.first, data)
|
|
12
12
|
args[1..].each do |arg|
|
|
13
13
|
current = JsonLogic.apply(arg, data)
|
|
14
|
-
|
|
15
|
-
return false unless prev.to_f == current.to_f
|
|
16
|
-
else
|
|
17
|
-
return false unless prev.class == current.class && prev == current
|
|
18
|
-
end
|
|
14
|
+
return false unless strict_equal_value?(prev, current)
|
|
19
15
|
|
|
20
16
|
prev = current
|
|
21
17
|
end
|
|
22
18
|
true
|
|
23
19
|
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def strict_equal_value?(left, right)
|
|
24
|
+
if left.is_a?(Numeric) && right.is_a?(Numeric)
|
|
25
|
+
left.to_f == right.to_f
|
|
26
|
+
elsif left.is_a?(Array) || left.is_a?(Hash)
|
|
27
|
+
left.equal?(right)
|
|
28
|
+
else
|
|
29
|
+
left.class == right.class && left.eql?(right)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
24
32
|
end
|
|
@@ -11,14 +11,22 @@ class JsonLogic::Operations::StrictNotEqual < JsonLogic::LazyOperation
|
|
|
11
11
|
prev = JsonLogic.apply(args.first, data)
|
|
12
12
|
args[1..].each do |arg|
|
|
13
13
|
current = JsonLogic.apply(arg, data)
|
|
14
|
-
if
|
|
15
|
-
return false if prev.to_f == current.to_f
|
|
16
|
-
else
|
|
17
|
-
return false if prev.class == current.class && prev == current
|
|
18
|
-
end
|
|
14
|
+
return false if strict_equal_value?(prev, current)
|
|
19
15
|
|
|
20
16
|
prev = current
|
|
21
17
|
end
|
|
22
18
|
true
|
|
23
19
|
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def strict_equal_value?(left, right)
|
|
24
|
+
if left.is_a?(Numeric) && right.is_a?(Numeric)
|
|
25
|
+
left.to_f == right.to_f
|
|
26
|
+
elsif left.is_a?(Array) || left.is_a?(Hash)
|
|
27
|
+
left.equal?(right)
|
|
28
|
+
else
|
|
29
|
+
left.class == right.class && left.eql?(right)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
24
32
|
end
|
data/lib/json_logic/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: json-logic-rb
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.0
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tavrel Kate
|
|
@@ -78,11 +78,11 @@ files:
|
|
|
78
78
|
- spec/tmp/v1/tests.json
|
|
79
79
|
- spec/tmp/v2/tests.json
|
|
80
80
|
- test/selftest.rb
|
|
81
|
-
homepage: https://
|
|
81
|
+
homepage: https://jsonlogic.com
|
|
82
82
|
licenses:
|
|
83
83
|
- MIT
|
|
84
84
|
metadata:
|
|
85
|
-
homepage_uri: https://
|
|
85
|
+
homepage_uri: https://jsonlogic.com
|
|
86
86
|
source_code_uri: https://github.com/tavrelkate/json-logic-rb
|
|
87
87
|
documentation_uri: https://github.com/tavrelkate/json-logic-rb
|
|
88
88
|
changelog_uri: https://github.com/tavrelkate/json-logic-rb/blob/main/CHANGELOG.md
|
|
@@ -102,5 +102,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
102
102
|
requirements: []
|
|
103
103
|
rubygems_version: 3.6.2
|
|
104
104
|
specification_version: 4
|
|
105
|
-
summary: Ruby implementation of JsonLogic
|
|
105
|
+
summary: Ruby implementation of JsonLogic. Pure and extensible. Full compliance.
|
|
106
106
|
test_files: []
|