json-logic-rb 0.1.0.beta1

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.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +315 -0
  4. data/lib/json_logic/engine.rb +54 -0
  5. data/lib/json_logic/enumerable_operation.rb +9 -0
  6. data/lib/json_logic/lazy_operation.rb +3 -0
  7. data/lib/json_logic/operation.rb +14 -0
  8. data/lib/json_logic/operations/add.rb +6 -0
  9. data/lib/json_logic/operations/all.rb +16 -0
  10. data/lib/json_logic/operations/and.rb +14 -0
  11. data/lib/json_logic/operations/bool_cast.rb +9 -0
  12. data/lib/json_logic/operations/cat.rb +6 -0
  13. data/lib/json_logic/operations/div.rb +6 -0
  14. data/lib/json_logic/operations/equal.rb +6 -0
  15. data/lib/json_logic/operations/filter.rb +15 -0
  16. data/lib/json_logic/operations/gt.rb +6 -0
  17. data/lib/json_logic/operations/gte.rb +6 -0
  18. data/lib/json_logic/operations/if.rb +15 -0
  19. data/lib/json_logic/operations/in_op.rb +6 -0
  20. data/lib/json_logic/operations/lt.rb +10 -0
  21. data/lib/json_logic/operations/lte.rb +10 -0
  22. data/lib/json_logic/operations/map.rb +10 -0
  23. data/lib/json_logic/operations/max.rb +6 -0
  24. data/lib/json_logic/operations/merge.rb +8 -0
  25. data/lib/json_logic/operations/min.rb +6 -0
  26. data/lib/json_logic/operations/missing.rb +33 -0
  27. data/lib/json_logic/operations/missing_some.rb +27 -0
  28. data/lib/json_logic/operations/mod.rb +6 -0
  29. data/lib/json_logic/operations/mul.rb +6 -0
  30. data/lib/json_logic/operations/none.rb +14 -0
  31. data/lib/json_logic/operations/not.rb +6 -0
  32. data/lib/json_logic/operations/not_equal.rb +6 -0
  33. data/lib/json_logic/operations/or.rb +12 -0
  34. data/lib/json_logic/operations/reduce.rb +19 -0
  35. data/lib/json_logic/operations/some.rb +16 -0
  36. data/lib/json_logic/operations/strict_equal.rb +6 -0
  37. data/lib/json_logic/operations/strict_not_equal.rb +6 -0
  38. data/lib/json_logic/operations/sub.rb +6 -0
  39. data/lib/json_logic/operations/substr.rb +30 -0
  40. data/lib/json_logic/operations/ternary.rb +13 -0
  41. data/lib/json_logic/operations/var.rb +27 -0
  42. data/lib/json_logic/registry.rb +19 -0
  43. data/lib/json_logic/semantics.rb +41 -0
  44. data/lib/json_logic/version.rb +3 -0
  45. data/lib/json_logic.rb +42 -0
  46. data/script/compliance.rb +50 -0
  47. data/spec/tmp/tests.js +0 -0
  48. data/spec/tmp/tests.json +532 -0
  49. data/test/selftest.rb +15 -0
  50. metadata +96 -0
@@ -0,0 +1,532 @@
1
+ [
2
+ "# Non-rules get passed through",
3
+ [ true, {}, true ],
4
+ [ false, {}, false ],
5
+ [ 17, {}, 17 ],
6
+ [ 3.14, {}, 3.14 ],
7
+ [ "apple", {}, "apple" ],
8
+ [ null, {}, null ],
9
+ [ ["a","b"], {}, ["a","b"] ],
10
+
11
+ "# Single operator tests",
12
+ [ {"==":[1,1]}, {}, true ],
13
+ [ {"==":[1,"1"]}, {}, true ],
14
+ [ {"==":[1,2]}, {}, false ],
15
+ [ {"===":[1,1]}, {}, true ],
16
+ [ {"===":[1,"1"]}, {}, false ],
17
+ [ {"===":[1,2]}, {}, false ],
18
+ [ {"!=":[1,2]}, {}, true ],
19
+ [ {"!=":[1,1]}, {}, false ],
20
+ [ {"!=":[1,"1"]}, {}, false ],
21
+ [ {"!==":[1,2]}, {}, true ],
22
+ [ {"!==":[1,1]}, {}, false ],
23
+ [ {"!==":[1,"1"]}, {}, true ],
24
+ [ {">":[2,1]}, {}, true ],
25
+ [ {">":[1,1]}, {}, false ],
26
+ [ {">":[1,2]}, {}, false ],
27
+ [ {">":["2",1]}, {}, true ],
28
+ [ {">=":[2,1]}, {}, true ],
29
+ [ {">=":[1,1]}, {}, true ],
30
+ [ {">=":[1,2]}, {}, false ],
31
+ [ {">=":["2",1]}, {}, true ],
32
+ [ {"<":[2,1]}, {}, false ],
33
+ [ {"<":[1,1]}, {}, false ],
34
+ [ {"<":[1,2]}, {}, true ],
35
+ [ {"<":["1",2]}, {}, true ],
36
+ [ {"<":[1,2,3]}, {}, true ],
37
+ [ {"<":[1,1,3]}, {}, false ],
38
+ [ {"<":[1,4,3]}, {}, false ],
39
+ [ {"<=":[2,1]}, {}, false ],
40
+ [ {"<=":[1,1]}, {}, true ],
41
+ [ {"<=":[1,2]}, {}, true ],
42
+ [ {"<=":["1",2]}, {}, true ],
43
+ [ {"<=":[1,2,3]}, {}, true ],
44
+ [ {"<=":[1,4,3]}, {}, false ],
45
+ [ {"!":[false]}, {}, true ],
46
+ [ {"!":false}, {}, true ],
47
+ [ {"!":[true]}, {}, false ],
48
+ [ {"!":true}, {}, false ],
49
+ [ {"!":0}, {}, true ],
50
+ [ {"!":1}, {}, false ],
51
+ [ {"or":[true,true]}, {}, true ],
52
+ [ {"or":[false,true]}, {}, true ],
53
+ [ {"or":[true,false]}, {}, true ],
54
+ [ {"or":[false,false]}, {}, false ],
55
+ [ {"or":[false,false,true]}, {}, true ],
56
+ [ {"or":[false,false,false]}, {}, false ],
57
+ [ {"or":[false]}, {}, false ],
58
+ [ {"or":[true]}, {}, true ],
59
+ [ {"or":[1,3]}, {}, 1 ],
60
+ [ {"or":[3,false]}, {}, 3 ],
61
+ [ {"or":[false,3]}, {}, 3 ],
62
+ [ {"and":[true,true]}, {}, true ],
63
+ [ {"and":[false,true]}, {}, false ],
64
+ [ {"and":[true,false]}, {}, false ],
65
+ [ {"and":[false,false]}, {}, false ],
66
+ [ {"and":[true,true,true]}, {}, true ],
67
+ [ {"and":[true,true,false]}, {}, false ],
68
+ [ {"and":[false]}, {}, false ],
69
+ [ {"and":[true]}, {}, true ],
70
+ [ {"and":[1,3]}, {}, 3 ],
71
+ [ {"and":[3,false]}, {}, false ],
72
+ [ {"and":[false,3]}, {}, false ],
73
+ [ {"?:":[true,1,2]}, {}, 1 ],
74
+ [ {"?:":[false,1,2]}, {}, 2 ],
75
+ [ {"in":["Bart",["Bart","Homer","Lisa","Marge","Maggie"]]}, {}, true ],
76
+ [ {"in":["Milhouse",["Bart","Homer","Lisa","Marge","Maggie"]]}, {}, false ],
77
+ [ {"in":["Spring","Springfield"]}, {}, true ],
78
+ [ {"in":["i","team"]}, {}, false ],
79
+ [ {"cat":"ice"}, {}, "ice" ],
80
+ [ {"cat":["ice"]}, {}, "ice" ],
81
+ [ {"cat":["ice","cream"]}, {}, "icecream" ],
82
+ [ {"cat":[1,2]}, {}, "12" ],
83
+ [ {"cat":["Robocop",2]}, {}, "Robocop2" ],
84
+ [ {"cat":["we all scream for ","ice","cream"]}, {}, "we all scream for icecream" ],
85
+ [ {"%":[1,2]}, {}, 1 ],
86
+ [ {"%":[2,2]}, {}, 0 ],
87
+ [ {"%":[3,2]}, {}, 1 ],
88
+ [ {"max":[1,2,3]}, {}, 3 ],
89
+ [ {"max":[1,3,3]}, {}, 3 ],
90
+ [ {"max":[3,2,1]}, {}, 3 ],
91
+ [ {"max":[1]}, {}, 1 ],
92
+ [ {"min":[1,2,3]}, {}, 1 ],
93
+ [ {"min":[1,1,3]}, {}, 1 ],
94
+ [ {"min":[3,2,1]}, {}, 1 ],
95
+ [ {"min":[1]}, {}, 1 ],
96
+
97
+ [ {"+":[1,2]}, {}, 3 ],
98
+ [ {"+":[2,2,2]}, {}, 6 ],
99
+ [ {"+":[1]}, {}, 1 ],
100
+ [ {"+":["1",1]}, {}, 2 ],
101
+ [ {"*":[3,2]}, {}, 6 ],
102
+ [ {"*":[2,2,2]}, {}, 8 ],
103
+ [ {"*":[1]}, {}, 1 ],
104
+ [ {"*":["1",1]}, {}, 1 ],
105
+ [ {"-":[2,3]}, {}, -1 ],
106
+ [ {"-":[3,2]}, {}, 1 ],
107
+ [ {"-":[3]}, {}, -3 ],
108
+ [ {"-":["1",1]}, {}, 0 ],
109
+ [ {"/":[4,2]}, {}, 2 ],
110
+ [ {"/":[2,4]}, {}, 0.5 ],
111
+ [ {"/":["1",1]}, {}, 1 ],
112
+
113
+ "Substring",
114
+ [{"substr":["jsonlogic", 4]}, null, "logic"],
115
+ [{"substr":["jsonlogic", -5]}, null, "logic"],
116
+ [{"substr":["jsonlogic", 0, 1]}, null, "j"],
117
+ [{"substr":["jsonlogic", -1, 1]}, null, "c"],
118
+ [{"substr":["jsonlogic", 4, 5]}, null, "logic"],
119
+ [{"substr":["jsonlogic", -5, 5]}, null, "logic"],
120
+ [{"substr":["jsonlogic", -5, -2]}, null, "log"],
121
+ [{"substr":["jsonlogic", 1, -5]}, null, "son"],
122
+
123
+ "Merge arrays",
124
+ [{"merge":[]}, null, []],
125
+ [{"merge":[[1]]}, null, [1]],
126
+ [{"merge":[[1],[]]}, null, [1]],
127
+ [{"merge":[[1], [2]]}, null, [1,2]],
128
+ [{"merge":[[1], [2], [3]]}, null, [1,2,3]],
129
+ [{"merge":[[1, 2], [3]]}, null, [1,2,3]],
130
+ [{"merge":[[1], [2, 3]]}, null, [1,2,3]],
131
+ "Given non-array arguments, merge converts them to arrays",
132
+ [{"merge":1}, null, [1]],
133
+ [{"merge":[1,2]}, null, [1,2]],
134
+ [{"merge":[1,[2]]}, null, [1,2]],
135
+
136
+ "Too few args",
137
+ [{"if":[]}, null, null],
138
+ [{"if":[true]}, null, true],
139
+ [{"if":[false]}, null, false],
140
+ [{"if":["apple"]}, null, "apple"],
141
+
142
+ "Simple if/then/else cases",
143
+ [{"if":[true, "apple"]}, null, "apple"],
144
+ [{"if":[false, "apple"]}, null, null],
145
+ [{"if":[true, "apple", "banana"]}, null, "apple"],
146
+ [{"if":[false, "apple", "banana"]}, null, "banana"],
147
+
148
+ "Empty arrays are falsey",
149
+ [{"if":[ [], "apple", "banana"]}, null, "banana"],
150
+ [{"if":[ [1], "apple", "banana"]}, null, "apple"],
151
+ [{"if":[ [1,2,3,4], "apple", "banana"]}, null, "apple"],
152
+
153
+ "Empty strings are falsey, all other strings are truthy",
154
+ [{"if":[ "", "apple", "banana"]}, null, "banana"],
155
+ [{"if":[ "zucchini", "apple", "banana"]}, null, "apple"],
156
+ [{"if":[ "0", "apple", "banana"]}, null, "apple"],
157
+
158
+ "You can cast a string to numeric with a unary + ",
159
+ [{"===":[0,"0"]}, null, false],
160
+ [{"===":[0,{"+":"0"}]}, null, true],
161
+ [{"if":[ {"+":"0"}, "apple", "banana"]}, null, "banana"],
162
+ [{"if":[ {"+":"1"}, "apple", "banana"]}, null, "apple"],
163
+
164
+ "Zero is falsy, all other numbers are truthy",
165
+ [{"if":[ 0, "apple", "banana"]}, null, "banana"],
166
+ [{"if":[ 1, "apple", "banana"]}, null, "apple"],
167
+ [{"if":[ 3.1416, "apple", "banana"]}, null, "apple"],
168
+ [{"if":[ -1, "apple", "banana"]}, null, "apple"],
169
+
170
+ "Truthy and falsy definitions matter in Boolean operations",
171
+ [{"!" : [ [] ]}, {}, true],
172
+ [{"!!" : [ [] ]}, {}, false],
173
+ [{"and" : [ [], true ]}, {}, [] ],
174
+ [{"or" : [ [], true ]}, {}, true ],
175
+
176
+ [{"!" : [ 0 ]}, {}, true],
177
+ [{"!!" : [ 0 ]}, {}, false],
178
+ [{"and" : [ 0, true ]}, {}, 0 ],
179
+ [{"or" : [ 0, true ]}, {}, true ],
180
+
181
+ [{"!" : [ "" ]}, {}, true],
182
+ [{"!!" : [ "" ]}, {}, false],
183
+ [{"and" : [ "", true ]}, {}, "" ],
184
+ [{"or" : [ "", true ]}, {}, true ],
185
+
186
+ [{"!" : [ "0" ]}, {}, false],
187
+ [{"!!" : [ "0" ]}, {}, true],
188
+ [{"and" : [ "0", true ]}, {}, true ],
189
+ [{"or" : [ "0", true ]}, {}, "0" ],
190
+
191
+ "If the conditional is logic, it gets evaluated",
192
+ [{"if":[ {">":[2,1]}, "apple", "banana"]}, null, "apple"],
193
+ [{"if":[ {">":[1,2]}, "apple", "banana"]}, null, "banana"],
194
+
195
+ "If the consequents are logic, they get evaluated",
196
+ [{"if":[ true, {"cat":["ap","ple"]}, {"cat":["ba","na","na"]} ]}, null, "apple"],
197
+ [{"if":[ false, {"cat":["ap","ple"]}, {"cat":["ba","na","na"]} ]}, null, "banana"],
198
+
199
+ "If/then/elseif/then cases",
200
+ [{"if":[true, "apple", true, "banana"]}, null, "apple"],
201
+ [{"if":[true, "apple", false, "banana"]}, null, "apple"],
202
+ [{"if":[false, "apple", true, "banana"]}, null, "banana"],
203
+ [{"if":[false, "apple", false, "banana"]}, null, null],
204
+
205
+ [{"if":[true, "apple", true, "banana", "carrot"]}, null, "apple"],
206
+ [{"if":[true, "apple", false, "banana", "carrot"]}, null, "apple"],
207
+ [{"if":[false, "apple", true, "banana", "carrot"]}, null, "banana"],
208
+ [{"if":[false, "apple", false, "banana", "carrot"]}, null, "carrot"],
209
+
210
+ [{"if":[false, "apple", false, "banana", false, "carrot"]}, null, null],
211
+ [{"if":[false, "apple", false, "banana", false, "carrot", "date"]}, null, "date"],
212
+ [{"if":[false, "apple", false, "banana", true, "carrot", "date"]}, null, "carrot"],
213
+ [{"if":[false, "apple", true, "banana", false, "carrot", "date"]}, null, "banana"],
214
+ [{"if":[false, "apple", true, "banana", true, "carrot", "date"]}, null, "banana"],
215
+ [{"if":[true, "apple", false, "banana", false, "carrot", "date"]}, null, "apple"],
216
+ [{"if":[true, "apple", false, "banana", true, "carrot", "date"]}, null, "apple"],
217
+ [{"if":[true, "apple", true, "banana", false, "carrot", "date"]}, null, "apple"],
218
+ [{"if":[true, "apple", true, "banana", true, "carrot", "date"]}, null, "apple"],
219
+
220
+ "Arrays with logic",
221
+ [[1, {"var": "x"}, 3], {"x": 2}, [1, 2, 3]],
222
+ [{"if": [{"var": "x"}, [{"var": "y"}], 99]}, {"x": true, "y": 42}, [42]],
223
+
224
+ "# Compound Tests",
225
+ [ {"and":[{">":[3,1]},true]}, {}, true ],
226
+ [ {"and":[{">":[3,1]},false]}, {}, false ],
227
+ [ {"and":[{">":[3,1]},{"!":true}]}, {}, false ],
228
+ [ {"and":[{">":[3,1]},{"<":[1,3]}]}, {}, true ],
229
+ [ {"?:":[{">":[3,1]},"visible","hidden"]}, {}, "visible" ],
230
+
231
+ "# Data-Driven",
232
+ [ {"var":["a"]},{"a":1},1 ],
233
+ [ {"var":["b"]},{"a":1},null ],
234
+ [ {"var":["a"]},null,null ],
235
+ [ {"var":"a"},{"a":1},1 ],
236
+ [ {"var":"b"},{"a":1},null ],
237
+ [ {"var":"a"},null,null ],
238
+ [ {"var":["a", 1]},null,1 ],
239
+ [ {"var":["b", 2]},{"a":1},2 ],
240
+ [ {"var":"a.b"},{"a":{"b":"c"}},"c" ],
241
+ [ {"var":"a.q"},{"a":{"b":"c"}},null ],
242
+ [ {"var":["a.q", 9]},{"a":{"b":"c"}},9 ],
243
+ [ {"var":1}, ["apple","banana"], "banana" ],
244
+ [ {"var":"1"}, ["apple","banana"], "banana" ],
245
+ [ {"var":"1.1"}, ["apple",["banana","beer"]], "beer" ],
246
+ [ {"and":[{"<":[{"var":"temp"},110]},{"==":[{"var":"pie.filling"},"apple"]}]},{"temp":100,"pie":{"filling":"apple"}},true ],
247
+ [ {"var":[{"?:":[{"<":[{"var":"temp"},110]},"pie.filling","pie.eta"]}]},{"temp":100,"pie":{"filling":"apple","eta":"60s"}},"apple" ],
248
+ [ {"in":[{"var":"filling"},["apple","cherry"]]},{"filling":"apple"},true ],
249
+ [ {"var":"a.b.c"}, null, null ],
250
+ [ {"var":"a.b.c"}, {"a":null}, null ],
251
+ [ {"var":"a.b.c"}, {"a":{"b":null}}, null ],
252
+ [ {"var":""}, 1, 1 ],
253
+ [ {"var":null}, 1, 1 ],
254
+ [ {"var":[]}, 1, 1 ],
255
+
256
+ "Missing",
257
+ [{"missing":[]}, null, []],
258
+ [{"missing":["a"]}, null, ["a"]],
259
+ [{"missing":"a"}, null, ["a"]],
260
+ [{"missing":"a"}, {"a":"apple"}, []],
261
+ [{"missing":["a"]}, {"a":"apple"}, []],
262
+ [{"missing":["a","b"]}, {"a":"apple"}, ["b"]],
263
+ [{"missing":["a","b"]}, {"b":"banana"}, ["a"]],
264
+ [{"missing":["a","b"]}, {"a":"apple", "b":"banana"}, []],
265
+ [{"missing":["a","b"]}, {}, ["a","b"]],
266
+ [{"missing":["a","b"]}, null, ["a","b"]],
267
+
268
+ [{"missing":["a.b"]}, null, ["a.b"]],
269
+ [{"missing":["a.b"]}, {"a":"apple"}, ["a.b"]],
270
+ [{"missing":["a.b"]}, {"a":{"c":"apple cake"}}, ["a.b"]],
271
+ [{"missing":["a.b"]}, {"a":{"b":"apple brownie"}}, []],
272
+ [{"missing":["a.b", "a.c"]}, {"a":{"b":"apple brownie"}}, ["a.c"]],
273
+
274
+
275
+ "Missing some",
276
+ [{"missing_some":[1, ["a", "b"]]}, {"a":"apple"}, [] ],
277
+ [{"missing_some":[1, ["a", "b"]]}, {"b":"banana"}, [] ],
278
+ [{"missing_some":[1, ["a", "b"]]}, {"a":"apple", "b":"banana"}, [] ],
279
+ [{"missing_some":[1, ["a", "b"]]}, {"c":"carrot"}, ["a", "b"]],
280
+
281
+ [{"missing_some":[2, ["a", "b", "c"]]}, {"a":"apple", "b":"banana"}, [] ],
282
+ [{"missing_some":[2, ["a", "b", "c"]]}, {"a":"apple", "c":"carrot"}, [] ],
283
+ [{"missing_some":[2, ["a", "b", "c"]]}, {"a":"apple", "b":"banana", "c":"carrot"}, [] ],
284
+ [{"missing_some":[2, ["a", "b", "c"]]}, {"a":"apple", "d":"durian"}, ["b", "c"] ],
285
+ [{"missing_some":[2, ["a", "b", "c"]]}, {"d":"durian", "e":"eggplant"}, ["a", "b", "c"] ],
286
+
287
+
288
+ "Missing and If are friends, because empty arrays are falsey in JsonLogic",
289
+ [{"if":[ {"missing":"a"}, "missed it", "found it" ]}, {"a":"apple"}, "found it"],
290
+ [{"if":[ {"missing":"a"}, "missed it", "found it" ]}, {"b":"banana"}, "missed it"],
291
+
292
+ "Missing, Merge, and If are friends. VIN is always required, APR is only required if financing is true.",
293
+ [
294
+ {"missing":{"merge":[ "vin", {"if": [{"var":"financing"}, ["apr"], [] ]} ]} },
295
+ {"financing":true},
296
+ ["vin","apr"]
297
+ ],
298
+
299
+ [
300
+ {"missing":{"merge":[ "vin", {"if": [{"var":"financing"}, ["apr"], [] ]} ]} },
301
+ {"financing":false},
302
+ ["vin"]
303
+ ],
304
+
305
+ "Filter, map, all, none, and some",
306
+ [
307
+ {"filter":[{"var":"integers"}, true]},
308
+ {"integers":[1,2,3]},
309
+ [1,2,3]
310
+ ],
311
+ [
312
+ {"filter":[{"var":"integers"}, false]},
313
+ {"integers":[1,2,3]},
314
+ []
315
+ ],
316
+ [
317
+ {"filter":[{"var":"integers"}, {">=":[{"var":""},2]}]},
318
+ {"integers":[1,2,3]},
319
+ [2,3]
320
+ ],
321
+ [
322
+ {"filter":[{"var":"integers"}, {"%":[{"var":""},2]}]},
323
+ {"integers":[1,2,3]},
324
+ [1,3]
325
+ ],
326
+
327
+ [
328
+ {"map":[{"var":"integers"}, {"*":[{"var":""},2]}]},
329
+ {"integers":[1,2,3]},
330
+ [2,4,6]
331
+ ],
332
+ [
333
+ {"map":[{"var":"integers"}, {"*":[{"var":""},2]}]},
334
+ null,
335
+ []
336
+ ],
337
+ [
338
+ {"map":[{"var":"desserts"}, {"var":"qty"}]},
339
+ {"desserts":[
340
+ {"name":"apple","qty":1},
341
+ {"name":"brownie","qty":2},
342
+ {"name":"cupcake","qty":3}
343
+ ]},
344
+ [1,2,3]
345
+ ],
346
+
347
+ [
348
+ {"reduce":[
349
+ {"var":"integers"},
350
+ {"+":[{"var":"current"}, {"var":"accumulator"}]},
351
+ 0
352
+ ]},
353
+ {"integers":[1,2,3,4]},
354
+ 10
355
+ ],
356
+ [
357
+ {"reduce":[
358
+ {"var":"integers"},
359
+ {"+":[{"var":"current"}, {"var":"accumulator"}]},
360
+ {"var": "start_with"}
361
+ ]},
362
+ {"integers":[1,2,3,4], "start_with": 59},
363
+ 69
364
+ ],
365
+ [
366
+ {"reduce":[
367
+ {"var":"integers"},
368
+ {"+":[{"var":"current"}, {"var":"accumulator"}]},
369
+ 0
370
+ ]},
371
+ null,
372
+ 0
373
+ ],
374
+ [
375
+ {"reduce":[
376
+ {"var":"integers"},
377
+ {"*":[{"var":"current"}, {"var":"accumulator"}]},
378
+ 1
379
+ ]},
380
+ {"integers":[1,2,3,4]},
381
+ 24
382
+ ],
383
+ [
384
+ {"reduce":[
385
+ {"var":"integers"},
386
+ {"*":[{"var":"current"}, {"var":"accumulator"}]},
387
+ 0
388
+ ]},
389
+ {"integers":[1,2,3,4]},
390
+ 0
391
+ ],
392
+ [
393
+ {"reduce": [
394
+ {"var":"desserts"},
395
+ {"+":[ {"var":"accumulator"}, {"var":"current.qty"}]},
396
+ 0
397
+ ]},
398
+ {"desserts":[
399
+ {"name":"apple","qty":1},
400
+ {"name":"brownie","qty":2},
401
+ {"name":"cupcake","qty":3}
402
+ ]},
403
+ 6
404
+ ],
405
+
406
+
407
+ [
408
+ {"all":[{"var":"integers"}, {">=":[{"var":""}, 1]}]},
409
+ {"integers":[1,2,3]},
410
+ true
411
+ ],
412
+ [
413
+ {"all":[{"var":"integers"}, {"==":[{"var":""}, 1]}]},
414
+ {"integers":[1,2,3]},
415
+ false
416
+ ],
417
+ [
418
+ {"all":[{"var":"integers"}, {"<":[{"var":""}, 1]}]},
419
+ {"integers":[1,2,3]},
420
+ false
421
+ ],
422
+ [
423
+ {"all":[{"var":"integers"}, {"<":[{"var":""}, 1]}]},
424
+ {"integers":[]},
425
+ false
426
+ ],
427
+ [
428
+ {"all":[ {"var":"items"}, {">=":[{"var":"qty"}, 1]}]},
429
+ {"items":[{"qty":1,"sku":"apple"},{"qty":2,"sku":"banana"}]},
430
+ true
431
+ ],
432
+ [
433
+ {"all":[ {"var":"items"}, {">":[{"var":"qty"}, 1]}]},
434
+ {"items":[{"qty":1,"sku":"apple"},{"qty":2,"sku":"banana"}]},
435
+ false
436
+ ],
437
+ [
438
+ {"all":[ {"var":"items"}, {"<":[{"var":"qty"}, 1]}]},
439
+ {"items":[{"qty":1,"sku":"apple"},{"qty":2,"sku":"banana"}]},
440
+ false
441
+ ],
442
+ [
443
+ {"all":[ {"var":"items"}, {">=":[{"var":"qty"}, 1]}]},
444
+ {"items":[]},
445
+ false
446
+ ],
447
+
448
+
449
+ [
450
+ {"none":[{"var":"integers"}, {">=":[{"var":""}, 1]}]},
451
+ {"integers":[1,2,3]},
452
+ false
453
+ ],
454
+ [
455
+ {"none":[{"var":"integers"}, {"==":[{"var":""}, 1]}]},
456
+ {"integers":[1,2,3]},
457
+ false
458
+ ],
459
+ [
460
+ {"none":[{"var":"integers"}, {"<":[{"var":""}, 1]}]},
461
+ {"integers":[1,2,3]},
462
+ true
463
+ ],
464
+ [
465
+ {"none":[{"var":"integers"}, {"<":[{"var":""}, 1]}]},
466
+ {"integers":[]},
467
+ true
468
+ ],
469
+ [
470
+ {"none":[ {"var":"items"}, {">=":[{"var":"qty"}, 1]}]},
471
+ {"items":[{"qty":1,"sku":"apple"},{"qty":2,"sku":"banana"}]},
472
+ false
473
+ ],
474
+ [
475
+ {"none":[ {"var":"items"}, {">":[{"var":"qty"}, 1]}]},
476
+ {"items":[{"qty":1,"sku":"apple"},{"qty":2,"sku":"banana"}]},
477
+ false
478
+ ],
479
+ [
480
+ {"none":[ {"var":"items"}, {"<":[{"var":"qty"}, 1]}]},
481
+ {"items":[{"qty":1,"sku":"apple"},{"qty":2,"sku":"banana"}]},
482
+ true
483
+ ],
484
+ [
485
+ {"none":[ {"var":"items"}, {">=":[{"var":"qty"}, 1]}]},
486
+ {"items":[]},
487
+ true
488
+ ],
489
+
490
+ [
491
+ {"some":[{"var":"integers"}, {">=":[{"var":""}, 1]}]},
492
+ {"integers":[1,2,3]},
493
+ true
494
+ ],
495
+ [
496
+ {"some":[{"var":"integers"}, {"==":[{"var":""}, 1]}]},
497
+ {"integers":[1,2,3]},
498
+ true
499
+ ],
500
+ [
501
+ {"some":[{"var":"integers"}, {"<":[{"var":""}, 1]}]},
502
+ {"integers":[1,2,3]},
503
+ false
504
+ ],
505
+ [
506
+ {"some":[{"var":"integers"}, {"<":[{"var":""}, 1]}]},
507
+ {"integers":[]},
508
+ false
509
+ ],
510
+ [
511
+ {"some":[ {"var":"items"}, {">=":[{"var":"qty"}, 1]}]},
512
+ {"items":[{"qty":1,"sku":"apple"},{"qty":2,"sku":"banana"}]},
513
+ true
514
+ ],
515
+ [
516
+ {"some":[ {"var":"items"}, {">":[{"var":"qty"}, 1]}]},
517
+ {"items":[{"qty":1,"sku":"apple"},{"qty":2,"sku":"banana"}]},
518
+ true
519
+ ],
520
+ [
521
+ {"some":[ {"var":"items"}, {"<":[{"var":"qty"}, 1]}]},
522
+ {"items":[{"qty":1,"sku":"apple"},{"qty":2,"sku":"banana"}]},
523
+ false
524
+ ],
525
+ [
526
+ {"some":[ {"var":"items"}, {">=":[{"var":"qty"}, 1]}]},
527
+ {"items":[]},
528
+ false
529
+ ],
530
+
531
+ "EOF"
532
+ ]
data/test/selftest.rb ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift File.expand_path('../lib', __dir__)
3
+ require 'json_logic'
4
+
5
+ def t(name)
6
+ print "[TEST] #{name} ... "
7
+ puts(yield ? 'OK' : 'FAIL')
8
+ end
9
+
10
+ t('add') { JsonLogic.apply({ '+' => [1, 2, 3] }) == 6.0 }
11
+ t('ge + var') { JsonLogic.apply({ '>=' => [{ 'var' => 'age' }, 18] }, { 'age' => 20 }) == true }
12
+ t('and short-circuit') { JsonLogic.apply({ 'and' => [false, { '/' => [1, 0] }] }) == false }
13
+ t('map inc') do
14
+ JsonLogic.apply({ 'map' => [{ 'var' => 'xs' }, { "+": [{ "var": '' }, 1] }] }, { 'xs' => [1, 2, 3] }) == [2, 3, 4]
15
+ end
metadata ADDED
@@ -0,0 +1,96 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: json-logic-rb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0.beta1
5
+ platform: ruby
6
+ authors:
7
+ - Tavrel Kate
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2025-10-06 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Ruby implementation of JsonLogic. JsonLogic rules are JSON trees. The
14
+ engine walks that tree and returns a Ruby value. Ships with a compliance runner
15
+ for the official test suite.
16
+ email:
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - LICENSE
22
+ - README.md
23
+ - lib/json_logic.rb
24
+ - lib/json_logic/engine.rb
25
+ - lib/json_logic/enumerable_operation.rb
26
+ - lib/json_logic/lazy_operation.rb
27
+ - lib/json_logic/operation.rb
28
+ - lib/json_logic/operations/add.rb
29
+ - lib/json_logic/operations/all.rb
30
+ - lib/json_logic/operations/and.rb
31
+ - lib/json_logic/operations/bool_cast.rb
32
+ - lib/json_logic/operations/cat.rb
33
+ - lib/json_logic/operations/div.rb
34
+ - lib/json_logic/operations/equal.rb
35
+ - lib/json_logic/operations/filter.rb
36
+ - lib/json_logic/operations/gt.rb
37
+ - lib/json_logic/operations/gte.rb
38
+ - lib/json_logic/operations/if.rb
39
+ - lib/json_logic/operations/in_op.rb
40
+ - lib/json_logic/operations/lt.rb
41
+ - lib/json_logic/operations/lte.rb
42
+ - lib/json_logic/operations/map.rb
43
+ - lib/json_logic/operations/max.rb
44
+ - lib/json_logic/operations/merge.rb
45
+ - lib/json_logic/operations/min.rb
46
+ - lib/json_logic/operations/missing.rb
47
+ - lib/json_logic/operations/missing_some.rb
48
+ - lib/json_logic/operations/mod.rb
49
+ - lib/json_logic/operations/mul.rb
50
+ - lib/json_logic/operations/none.rb
51
+ - lib/json_logic/operations/not.rb
52
+ - lib/json_logic/operations/not_equal.rb
53
+ - lib/json_logic/operations/or.rb
54
+ - lib/json_logic/operations/reduce.rb
55
+ - lib/json_logic/operations/some.rb
56
+ - lib/json_logic/operations/strict_equal.rb
57
+ - lib/json_logic/operations/strict_not_equal.rb
58
+ - lib/json_logic/operations/sub.rb
59
+ - lib/json_logic/operations/substr.rb
60
+ - lib/json_logic/operations/ternary.rb
61
+ - lib/json_logic/operations/var.rb
62
+ - lib/json_logic/registry.rb
63
+ - lib/json_logic/semantics.rb
64
+ - lib/json_logic/version.rb
65
+ - script/compliance.rb
66
+ - spec/tmp/tests.js
67
+ - spec/tmp/tests.json
68
+ - test/selftest.rb
69
+ homepage: https://github.com/tavrelkate/json-logic-rb
70
+ licenses:
71
+ - MIT
72
+ metadata:
73
+ homepage_uri: https://github.com/tavrelkate/json-logic-rb
74
+ source_code_uri: https://github.com/tavrelkate/json-logic-rb
75
+ documentation_uri: https://github.com/tavrelkate/json-logic-rb
76
+ changelog_uri: https://github.com/tavrelkate/json-logic-rb/blob/main/CHANGELOG.md
77
+ post_install_message:
78
+ rdoc_options: []
79
+ require_paths:
80
+ - lib
81
+ required_ruby_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: '3.0'
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ requirements: []
92
+ rubygems_version: 3.5.22
93
+ signing_key:
94
+ specification_version: 4
95
+ summary: Ruby implementation of JsonLogic — simple and extensible.
96
+ test_files: []