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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fe25d64cef43ddb57ad9f94bec45b401ce7ee19b29757108336644342f75f8e1
4
- data.tar.gz: 21e8ef8421a8768c8be32795c855cc52ec4a4afed79a5875399372417fa06da9
3
+ metadata.gz: bf7e4291a1fe0a56b1387ca35f03d239679f4d0c76333a3d0d0f3933efeead0b
4
+ data.tar.gz: 134bb254ff81c389daa1d9527b9496d17d0417316143586ea8ade75c739f2657
5
5
  SHA512:
6
- metadata.gz: e228a5ed37724d97e54c87e726f772e5f5a749a114a8b02a332bf9131da06c83fedaf0f5d059bd61c94c1c0be73c34ab9fc1cd9d6c6408c958159d951c3a36c9
7
- data.tar.gz: 805c23fe8af646123f4c5535111d14576ebbf6c1aeeaf6b01247bbc0dd92399e9584ddd869b4522b6a5734c601e701e7736b27b628ccc2cc576f7a26b211fe84
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) [![compliance 100%](https://img.shields.io/badge/compliance-100%25-brightgreen)](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/) elegant and extensible. Full compliance with both core and community-extended specifications.
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) [![compliance 100%](https://img.shields.io/badge/compliance-100%25-brightgreen)](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
- - [How](#how)
24
- - [1. Default Operations](#1-default-operations)
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
- **Groups and references:**
78
+ ## Complience
107
79
 
108
- - [Logic and Boolean Operations](https://jsonlogic.com/operations.html#logic-and-boolean-operations) short-circuit/branching like `or`.
109
- - [Comparison operations](https://jsonlogic.com/operations.html#logic-and-boolean-operations) equality/ordering like `==`.
110
- - [Array operations](https://jsonlogic.com/operations.html#array-operations) enumerable evaluation like `map`.
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
- Download test suite v1:
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` | ✅ | ![jsonlogic community](https://img.shields.io/badge/jsonlogic--community-extra-0366d6?style=flat-square) |
237
140
  | `preserve` | ✅ | ![jsonlogic community](https://img.shields.io/badge/jsonlogic--community-extra-0366d6?style=flat-square) |
238
141
  | Docs-only / Not implemented | | |
239
- | `log` | 🚫 | ![jsonlogic](https://img.shields.io/badge/jsonlogic-core-2ea44f?style=flat-square) |
142
+ | `log` | 🚫 | ![jsonlogic docs](https://img.shields.io/badge/jsonlogic-docs-6a737d?style=flat-square) |
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
- Need a custom Operation? It’s straightforward. Start small with a Proc or Lambda. If needed promote it to a Class.
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
- ### Enable JsonLogic Semantics (optional)
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 [§How](https://github.com/tavrelkate/json-logic-rb?tab=readme-ov-file#how) for details.
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
- ## Authors
354
+ ## Maintainers
395
355
 
396
- - [Valeriya Petrova](https://github.com/piatrova-valeriya1999)
356
+ - [Valeriya Petrova](https://github.com/valeryia-piatrova)
397
357
  - [Tavrel Kate](https://github.com/tavrelkate)
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ using JsonLogic::Semantics
4
+
3
5
  class JsonLogic::Operations::Missing < JsonLogic::Operation
4
6
  def self.name = "missing"
5
7
 
@@ -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
- if prev.is_a?(Numeric) && current.is_a?(Numeric)
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 prev.is_a?(Numeric) && current.is_a?(Numeric)
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
@@ -1,3 +1,3 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module JsonLogic; VERSION = '0.2.0.beta1'; end
3
+ module JsonLogic; VERSION = '0.2.0'; end
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.beta1
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://github.com/tavrelkate/json-logic-rb
81
+ homepage: https://jsonlogic.com
82
82
  licenses:
83
83
  - MIT
84
84
  metadata:
85
- homepage_uri: https://github.com/tavrelkate/json-logic-rb
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 elegant and extensible.
105
+ summary: Ruby implementation of JsonLogic. Pure and extensible. Full compliance.
106
106
  test_files: []