json-logic-rb 0.1.0 → 0.1.1.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.
- checksums.yaml +4 -4
- data/README.md +3 -3
- data/lib/json_logic/operation.rb +2 -0
- data/lib/json_logic/operations/add.rb +4 -1
- data/lib/json_logic/operations/all.rb +1 -3
- data/lib/json_logic/operations/and.rb +1 -1
- data/lib/json_logic/operations/bool_cast.rb +1 -1
- data/lib/json_logic/operations/cat.rb +1 -0
- data/lib/json_logic/operations/div.rb +1 -0
- data/lib/json_logic/operations/equal.rb +6 -1
- data/lib/json_logic/operations/filter.rb +1 -3
- data/lib/json_logic/operations/gt.rb +3 -1
- data/lib/json_logic/operations/gte.rb +6 -1
- data/lib/json_logic/operations/if.rb +1 -1
- data/lib/json_logic/operations/{in_op.rb → in.rb} +2 -1
- data/lib/json_logic/operations/lt.rb +5 -3
- data/lib/json_logic/operations/lte.rb +5 -3
- data/lib/json_logic/operations/max.rb +2 -1
- data/lib/json_logic/operations/min.rb +2 -1
- data/lib/json_logic/operations/missing_some.rb +1 -0
- data/lib/json_logic/operations/mod.rb +1 -0
- data/lib/json_logic/operations/none.rb +1 -3
- data/lib/json_logic/operations/not.rb +2 -1
- data/lib/json_logic/operations/not_equal.rb +6 -1
- data/lib/json_logic/operations/or.rb +2 -1
- data/lib/json_logic/operations/reduce.rb +1 -1
- data/lib/json_logic/operations/some.rb +1 -3
- data/lib/json_logic/operations/strict_equal.rb +4 -1
- data/lib/json_logic/operations/strict_not_equal.rb +4 -1
- data/lib/json_logic/operations/ternary.rb +1 -1
- data/lib/json_logic/operations/var.rb +4 -1
- data/lib/json_logic/semantics.rb +60 -22
- data/lib/json_logic/version.rb +1 -1
- metadata +3 -4
- data/spec/tmp/tests.js +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4d4064f94160ac9151244253f9a265932a0d30c43288523a73ef9bfcabb97b3b
|
|
4
|
+
data.tar.gz: e49615ccae718c4f8c87f5289e4d4e0c079a9bd516fd0e15399c978995d1599e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c73281072de2de418a28e3104b5e41fa084e57f8a2c4f2c4cd92bb2d0571d0cde87ffd36a86c7eefee03f690e916eb875fc1bf1800ab40faa9eba371afdc1230
|
|
7
|
+
data.tar.gz: 0a7759d9d56afca69ccc8d7dbd7e623007750288c29ad048719f64f202d124ad8e106545edb99b73489d4f6488df6989394e1bf330bf7e792d0a749d605d089e
|
data/README.md
CHANGED
|
@@ -21,7 +21,7 @@ Ruby implementation of [JsonLogic](https://jsonlogic.com/) — simple and extens
|
|
|
21
21
|
- [Miscellaneous](#miscellaneous)
|
|
22
22
|
- [Extending (add your own operator)](#extending-add-your-own-operator)
|
|
23
23
|
- [Public Interface](#public-interface)
|
|
24
|
-
- [Compliance & tests](#compliance
|
|
24
|
+
- [Compliance & tests](#compliance-and-tests)
|
|
25
25
|
- [Security](#security)
|
|
26
26
|
- [License](#license)
|
|
27
27
|
- [Contributing](#contributing)
|
|
@@ -107,7 +107,7 @@ The operator then evaluates only the sub-rules it actually needs.
|
|
|
107
107
|
|
|
108
108
|
**Examples**
|
|
109
109
|
```ruby
|
|
110
|
-
|
|
110
|
+
# filter: keep numbers >= 2
|
|
111
111
|
JsonLogic.apply(
|
|
112
112
|
{ "filter" => [ { "var" => "ints" }, { ">=" => [ { "var" => "" }, 2 ] } ] },
|
|
113
113
|
{ "ints" => [1,2,3] }
|
|
@@ -282,7 +282,7 @@ engine.registry.register(JsonLogic::Operations::StartsWith)
|
|
|
282
282
|
|
|
283
283
|
---
|
|
284
284
|
|
|
285
|
-
## Compliance
|
|
285
|
+
## Compliance and tests
|
|
286
286
|
Optional: quick self-test
|
|
287
287
|
|
|
288
288
|
```bash
|
data/lib/json_logic/operation.rb
CHANGED
|
@@ -8,9 +8,7 @@ class JsonLogic::Operations::All < JsonLogic::EnumerableOperation
|
|
|
8
8
|
return false if items.empty?
|
|
9
9
|
|
|
10
10
|
items.all? do |item|
|
|
11
|
-
|
|
12
|
-
JsonLogic.apply(rule_applied_to_each_item, item)
|
|
13
|
-
)
|
|
11
|
+
truthy?(JsonLogic.apply(rule_applied_to_each_item, item))
|
|
14
12
|
end
|
|
15
13
|
end
|
|
16
14
|
end
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
using JsonLogic::Semantics
|
|
4
|
+
|
|
3
5
|
class JsonLogic::Operations::Equal < JsonLogic::Operation
|
|
4
6
|
def self.op_name = "=="
|
|
5
|
-
|
|
7
|
+
|
|
8
|
+
def call((a,b), _data)
|
|
9
|
+
a == b
|
|
10
|
+
end
|
|
6
11
|
end
|
|
@@ -7,9 +7,7 @@ class JsonLogic::Operations::Filter < JsonLogic::EnumerableOperation
|
|
|
7
7
|
items, rule_applied_to_each_item = resolve_items_and_per_item_rule(args, data)
|
|
8
8
|
|
|
9
9
|
items.filter do |item|
|
|
10
|
-
|
|
11
|
-
JsonLogic.apply(rule_applied_to_each_item, item)
|
|
12
|
-
)
|
|
10
|
+
truthy?(JsonLogic.apply(rule_applied_to_each_item, item))
|
|
13
11
|
end
|
|
14
12
|
end
|
|
15
13
|
end
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
using JsonLogic::Semantics
|
|
4
|
+
|
|
3
5
|
class JsonLogic::Operations::GT < JsonLogic::Operation
|
|
4
6
|
def self.op_name = ">"
|
|
5
|
-
def call((a,b), _data) =
|
|
7
|
+
def call((a,b), _data) = a > b
|
|
6
8
|
end
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
using JsonLogic::Semantics
|
|
4
|
+
|
|
3
5
|
class JsonLogic::Operations::GTE < JsonLogic::Operation
|
|
4
6
|
def self.op_name = ">="
|
|
5
|
-
|
|
7
|
+
|
|
8
|
+
def call((a,b), _data)
|
|
9
|
+
a >= b
|
|
10
|
+
end
|
|
6
11
|
end
|
|
@@ -6,7 +6,7 @@ class JsonLogic::Operations::If < JsonLogic::LazyOperation
|
|
|
6
6
|
def call(args, data)
|
|
7
7
|
i = 0
|
|
8
8
|
while i < args.size - 1
|
|
9
|
-
return JsonLogic.apply(args[i + 1], data) if
|
|
9
|
+
return JsonLogic.apply(args[i + 1], data) if truthy?(JsonLogic.apply(args[i], data))
|
|
10
10
|
i += 2
|
|
11
11
|
end
|
|
12
12
|
return JsonLogic.apply(args[-1], data) if args.size.odd?
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
using JsonLogic::Semantics
|
|
4
|
+
|
|
3
5
|
class JsonLogic::Operations::LT < JsonLogic::Operation
|
|
4
6
|
def self.op_name = "<"
|
|
7
|
+
|
|
5
8
|
def call(values, _data)
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
nums.each_cons(2).all? { |a,b| a < b }
|
|
9
|
+
return values[0] < values[1] if values.size == 2
|
|
10
|
+
values.each_cons(2).all? { |a,b| a < b }
|
|
9
11
|
end
|
|
10
12
|
end
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
using JsonLogic::Semantics
|
|
4
|
+
|
|
3
5
|
class JsonLogic::Operations::LTE < JsonLogic::Operation
|
|
4
6
|
def self.op_name = "<="
|
|
7
|
+
|
|
5
8
|
def call(values, _data)
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
nums.each_cons(2).all? { |a,b| a <= b }
|
|
9
|
+
return values[0] <= values[1] if values.size == 2
|
|
10
|
+
values.each_cons(2).all? { |a,b| a <= b }
|
|
9
11
|
end
|
|
10
12
|
end
|
|
@@ -6,9 +6,7 @@ class JsonLogic::Operations::None < JsonLogic::EnumerableOperation
|
|
|
6
6
|
def call(args, data)
|
|
7
7
|
items, rule_applied_to_each_item = resolve_items_and_per_item_rule(args, data)
|
|
8
8
|
items.none? do |item|
|
|
9
|
-
|
|
10
|
-
JsonLogic.apply(rule_applied_to_each_item, item)
|
|
11
|
-
)
|
|
9
|
+
truthy?(JsonLogic.apply(rule_applied_to_each_item, item))
|
|
12
10
|
end
|
|
13
11
|
end
|
|
14
12
|
end
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
using JsonLogic::Semantics
|
|
4
|
+
|
|
3
5
|
class JsonLogic::Operations::NotEqual < JsonLogic::Operation
|
|
4
6
|
def self.op_name = "!="
|
|
5
|
-
|
|
7
|
+
|
|
8
|
+
def call((a,b), _data)
|
|
9
|
+
!(a == b)
|
|
10
|
+
end
|
|
6
11
|
end
|
|
@@ -5,8 +5,9 @@ class JsonLogic::Operations::Or < JsonLogic::LazyOperation
|
|
|
5
5
|
def call(args, data)
|
|
6
6
|
args.each do |a|
|
|
7
7
|
v = JsonLogic.apply(a, data)
|
|
8
|
-
return v if
|
|
8
|
+
return v if truthy?(v)
|
|
9
9
|
end
|
|
10
|
+
|
|
10
11
|
args.empty? ? nil : JsonLogic.apply(args.last, data)
|
|
11
12
|
end
|
|
12
13
|
end
|
|
@@ -8,9 +8,7 @@ class JsonLogic::Operations::Some < JsonLogic::EnumerableOperation
|
|
|
8
8
|
return false if items.empty?
|
|
9
9
|
|
|
10
10
|
items.any? do |item|
|
|
11
|
-
|
|
12
|
-
JsonLogic.apply(rule_applied_to_each_item, item)
|
|
13
|
-
)
|
|
11
|
+
truthy?(JsonLogic.apply(rule_applied_to_each_item, item))
|
|
14
12
|
end
|
|
15
13
|
end
|
|
16
14
|
end
|
|
@@ -4,7 +4,7 @@ class JsonLogic::Operations::Ternary < JsonLogic::LazyOperation
|
|
|
4
4
|
def self.op_name = "?:"
|
|
5
5
|
|
|
6
6
|
def call((cond_rule, then_rule, else_rule), data)
|
|
7
|
-
if
|
|
7
|
+
if truthy?(JsonLogic.apply(cond_rule, data))
|
|
8
8
|
JsonLogic.apply(then_rule, data)
|
|
9
9
|
else
|
|
10
10
|
JsonLogic.apply(else_rule, data)
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
class JsonLogic::Operations::Var < JsonLogic::Operation
|
|
4
|
-
def self.op_name = "var";
|
|
4
|
+
def self.op_name = "var";
|
|
5
|
+
def self.values_only? = false
|
|
6
|
+
|
|
5
7
|
def call((path_rule, fallback_rule), data)
|
|
6
8
|
path = JsonLogic.apply(path_rule, data)
|
|
7
9
|
return data if path == ""
|
|
@@ -10,6 +12,7 @@ class JsonLogic::Operations::Var < JsonLogic::Operation
|
|
|
10
12
|
return nil if fallback_rule.nil?
|
|
11
13
|
JsonLogic.apply(fallback_rule, data)
|
|
12
14
|
end
|
|
15
|
+
|
|
13
16
|
def dig(obj, path)
|
|
14
17
|
return nil if obj.nil?
|
|
15
18
|
cur = obj
|
data/lib/json_logic/semantics.rb
CHANGED
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
module JsonLogic
|
|
4
4
|
module Semantics
|
|
5
|
-
NUMERIC_RE = /\A[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?\z/.freeze
|
|
6
|
-
|
|
7
5
|
module_function
|
|
8
6
|
|
|
9
7
|
def truthy?(v)
|
|
@@ -11,42 +9,82 @@ module JsonLogic
|
|
|
11
9
|
when nil then false
|
|
12
10
|
when TrueClass, FalseClass then v
|
|
13
11
|
when Numeric then !v.zero?
|
|
14
|
-
when String then !v.empty?
|
|
15
|
-
when Array then !v.empty?
|
|
12
|
+
when String, Array then !v.empty?
|
|
16
13
|
else true
|
|
17
14
|
end
|
|
18
15
|
end
|
|
19
16
|
|
|
20
|
-
def
|
|
21
|
-
|
|
22
|
-
def to_number(v)
|
|
17
|
+
def num(v)
|
|
23
18
|
case v
|
|
24
|
-
when
|
|
25
|
-
when
|
|
19
|
+
when Numeric then v.to_f
|
|
20
|
+
when TrueClass then 1.0
|
|
21
|
+
when FalseClass then 0.0
|
|
22
|
+
when NilClass then 0.0
|
|
23
|
+
when Array then num(v.join(','))
|
|
26
24
|
when String
|
|
27
25
|
s = v.strip
|
|
28
|
-
return
|
|
29
|
-
s
|
|
26
|
+
return 0.0 if s.empty?
|
|
27
|
+
Float(s) rescue Float::NAN
|
|
30
28
|
else
|
|
31
|
-
|
|
29
|
+
Float::NAN
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def eq(a, b)
|
|
34
|
+
if a.class == b.class
|
|
35
|
+
return false if a.is_a?(Numeric) && (a.to_f.nan? || b.to_f.nan?)
|
|
36
|
+
return a.is_a?(Numeric) ? (a.to_f == b.to_f) : a.eql?(b)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
if a == true || a == false || b == true || b == false
|
|
40
|
+
na = num(a); nb = num(b)
|
|
41
|
+
return false if na.nan? || nb.nan?
|
|
42
|
+
return na == nb
|
|
32
43
|
end
|
|
44
|
+
|
|
45
|
+
if (a.is_a?(String) && b.is_a?(Numeric)) || (a.is_a?(Numeric) && b.is_a?(String))
|
|
46
|
+
na = num(a); nb = num(b)
|
|
47
|
+
return false if na.nan? || nb.nan?
|
|
48
|
+
return na == nb
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
false
|
|
33
52
|
end
|
|
34
53
|
|
|
35
|
-
def
|
|
36
|
-
if a.is_a?(
|
|
37
|
-
a
|
|
54
|
+
def cmp(a, b)
|
|
55
|
+
if a.is_a?(String) && b.is_a?(String)
|
|
56
|
+
a <=> b
|
|
38
57
|
else
|
|
39
|
-
|
|
58
|
+
x = num(a); y = num(b)
|
|
59
|
+
return nil if x.nan? || y.nan?
|
|
60
|
+
x <=> y
|
|
40
61
|
end
|
|
41
62
|
end
|
|
42
63
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
64
|
+
[String, Integer, TrueClass, FalseClass, NilClass, Array].each do |klass|
|
|
65
|
+
refine klass do
|
|
66
|
+
def ==(other) = JsonLogic::Semantics.eq(self, other)
|
|
67
|
+
|
|
68
|
+
def >(other)
|
|
69
|
+
c = JsonLogic::Semantics.cmp(self, other)
|
|
70
|
+
c && c == 1
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def >=(other)
|
|
74
|
+
c = JsonLogic::Semantics.cmp(self, other)
|
|
75
|
+
c && (c == 1 || c == 0)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def <(other)
|
|
79
|
+
c = JsonLogic::Semantics.cmp(self, other)
|
|
80
|
+
c && c == -1
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def <=(other)
|
|
84
|
+
c = JsonLogic::Semantics.cmp(self, other)
|
|
85
|
+
c && (c == -1 || c == 0)
|
|
86
|
+
end
|
|
48
87
|
end
|
|
49
|
-
a == b
|
|
50
88
|
end
|
|
51
89
|
end
|
|
52
90
|
end
|
data/lib/json_logic/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: json-logic-rb
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.1.beta1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tavrel Kate
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2025-10-
|
|
11
|
+
date: 2025-10-30 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: Ruby implementation of JsonLogic. JsonLogic rules are JSON trees. The
|
|
14
14
|
engine walks that tree and returns a Ruby value. Ships with a compliance runner
|
|
@@ -36,7 +36,7 @@ files:
|
|
|
36
36
|
- lib/json_logic/operations/gt.rb
|
|
37
37
|
- lib/json_logic/operations/gte.rb
|
|
38
38
|
- lib/json_logic/operations/if.rb
|
|
39
|
-
- lib/json_logic/operations/
|
|
39
|
+
- lib/json_logic/operations/in.rb
|
|
40
40
|
- lib/json_logic/operations/lt.rb
|
|
41
41
|
- lib/json_logic/operations/lte.rb
|
|
42
42
|
- lib/json_logic/operations/map.rb
|
|
@@ -63,7 +63,6 @@ files:
|
|
|
63
63
|
- lib/json_logic/semantics.rb
|
|
64
64
|
- lib/json_logic/version.rb
|
|
65
65
|
- script/compliance.rb
|
|
66
|
-
- spec/tmp/tests.js
|
|
67
66
|
- spec/tmp/tests.json
|
|
68
67
|
- test/selftest.rb
|
|
69
68
|
homepage: https://github.com/tavrelkate/json-logic-rb
|
data/spec/tmp/tests.js
DELETED
|
File without changes
|