shiny_json_logic 0.2.16 → 0.3.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/CHANGELOG.md +4 -0
- data/Gemfile.lock +1 -1
- data/README.md +1 -5
- data/lib/shiny_json_logic/comparisons/comparable.rb +27 -4
- data/lib/shiny_json_logic/engine.rb +1 -1
- data/lib/shiny_json_logic/numericals/min_max_collection.rb +9 -14
- data/lib/shiny_json_logic/numericals/numerify.rb +5 -5
- data/lib/shiny_json_logic/numericals/with_error_handling.rb +2 -0
- data/lib/shiny_json_logic/operations/addition.rb +5 -23
- data/lib/shiny_json_logic/operations/all.rb +1 -3
- data/lib/shiny_json_logic/operations/and.rb +3 -4
- data/lib/shiny_json_logic/operations/base.rb +13 -31
- data/lib/shiny_json_logic/operations/coalesce.rb +2 -2
- data/lib/shiny_json_logic/operations/concatenation.rb +4 -4
- data/lib/shiny_json_logic/operations/different.rb +2 -17
- data/lib/shiny_json_logic/operations/division.rb +6 -14
- data/lib/shiny_json_logic/operations/double_not.rb +3 -3
- data/lib/shiny_json_logic/operations/equal.rb +2 -16
- data/lib/shiny_json_logic/operations/exists.rb +4 -4
- data/lib/shiny_json_logic/operations/filter.rb +2 -4
- data/lib/shiny_json_logic/operations/greater.rb +2 -17
- data/lib/shiny_json_logic/operations/greater_equal.rb +2 -17
- data/lib/shiny_json_logic/operations/if.rb +5 -16
- data/lib/shiny_json_logic/operations/inclusion.rb +3 -3
- data/lib/shiny_json_logic/operations/iterable/base.rb +31 -61
- data/lib/shiny_json_logic/operations/max.rb +2 -4
- data/lib/shiny_json_logic/operations/merge.rb +3 -3
- data/lib/shiny_json_logic/operations/min.rb +2 -4
- data/lib/shiny_json_logic/operations/missing.rb +10 -10
- data/lib/shiny_json_logic/operations/missing_some.rb +7 -6
- data/lib/shiny_json_logic/operations/modulo.rb +6 -14
- data/lib/shiny_json_logic/operations/none.rb +1 -3
- data/lib/shiny_json_logic/operations/not.rb +2 -2
- data/lib/shiny_json_logic/operations/or.rb +3 -4
- data/lib/shiny_json_logic/operations/preserve.rb +8 -25
- data/lib/shiny_json_logic/operations/product.rb +7 -20
- data/lib/shiny_json_logic/operations/reduce.rb +24 -30
- data/lib/shiny_json_logic/operations/smaller.rb +2 -17
- data/lib/shiny_json_logic/operations/smaller_equal.rb +2 -17
- data/lib/shiny_json_logic/operations/some.rb +1 -3
- data/lib/shiny_json_logic/operations/strict_different.rb +6 -12
- data/lib/shiny_json_logic/operations/strict_equal.rb +6 -12
- data/lib/shiny_json_logic/operations/substring.rb +4 -4
- data/lib/shiny_json_logic/operations/subtraction.rb +7 -20
- data/lib/shiny_json_logic/operations/throw.rb +5 -7
- data/lib/shiny_json_logic/operations/try.rb +2 -3
- data/lib/shiny_json_logic/operations/val.rb +14 -22
- data/lib/shiny_json_logic/operations/var.rb +13 -15
- data/lib/shiny_json_logic/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: df6cbb1873a1d4237a634ab972f9da4f2e1b56012f0e9353e34c723746f75655
|
|
4
|
+
data.tar.gz: b62ce7480cdbab13df690836b3c837b96b360d08fb6cd0c86ee8e743222234bc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cb846733714d95672c98d615c1474582e5516d13e02becbe13a9839d7571d7f2792235595777464b53c5e4173ea8af49d5d721d09283bfa72ade52f231bb74f7
|
|
7
|
+
data.tar.gz: 121d271417ace9b145dfc92861e7857ff8c22eb859a7a8d9f2d8ff6b37708a1ee3c55a22f60cf925c1826c41622012848a2a54dd3f4afc9b8084b4ae6424a8e1
|
data/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
|
+
## [0.3.0] - 2026-02-21
|
|
5
|
+
### Changed
|
|
6
|
+
- Refactors internal architecture to improve performance by removing instantiation of operations.
|
|
7
|
+
|
|
4
8
|
## [0.2.16] - 2026-02-21
|
|
5
9
|
### Changed
|
|
6
10
|
- Removed simple delegator to check indifferent access in favour of key transformation . This improves performance and reduces memory usage.
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -18,13 +18,12 @@ This gem focuses on predictable behavior, strict spec alignment, high compatibil
|
|
|
18
18
|
- 🕰️ **Ruby 2.7+ compatible**, one of the lowest minimum versions supported in the Ruby ecosystem.
|
|
19
19
|
- 🔧 **Actively maintained** and continuously improved.
|
|
20
20
|
- 📊 **Highest JSONLogic compatibility in the Ruby ecosystem**, as measured against the official test suites.
|
|
21
|
-
- ⭐ **Only Ruby implementation supporting the latest standard operators** (`val`, `exists`, `??`, `try`, `throw`)
|
|
22
21
|
|
|
23
22
|
If you want JSON Logic to *just work* in Ruby, this is the safe default.
|
|
24
23
|
|
|
25
24
|
---
|
|
26
25
|
# Test it for yourself!
|
|
27
|
-
Try it out in the sandbox at [jsonlogicruby.com](https://jsonlogicruby.com)
|
|
26
|
+
Try it out in the sandbox at [jsonlogicruby.com](https://jsonlogicruby.com/playground) or run the official test suite with `bin/test.sh` to see the compatibility for yourself.
|
|
28
27
|
|
|
29
28
|
---
|
|
30
29
|
|
|
@@ -158,9 +157,6 @@ Currently implemented operators include:
|
|
|
158
157
|
### Evaluation
|
|
159
158
|
`preserve`✨
|
|
160
159
|
|
|
161
|
-
📌 **Note:**
|
|
162
|
-
`val`, `exists`, `??`, `try`, `throw` and `preserve` are **only supported by ShinyJsonLogic** among Ruby implementations.
|
|
163
|
-
|
|
164
160
|
See the [spec](https://jsonlogicruby.com/docs) for the full list of operators and their behavior.
|
|
165
161
|
|
|
166
162
|
---
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "shiny_json_logic/numericals/numerify"
|
|
4
|
+
require "shiny_json_logic/errors/not_a_number"
|
|
5
|
+
require "shiny_json_logic/errors/invalid_arguments"
|
|
4
6
|
|
|
5
7
|
module ShinyJsonLogic
|
|
6
8
|
module Comparisons
|
|
7
9
|
module Comparable
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
private
|
|
10
|
+
module_function
|
|
11
11
|
|
|
12
12
|
def compare(a, b)
|
|
13
13
|
return :nan if a.is_a?(Array) || a.is_a?(Hash) || b.is_a?(Array) || b.is_a?(Hash)
|
|
@@ -28,9 +28,32 @@ module ShinyJsonLogic
|
|
|
28
28
|
return 0.0 if value == false
|
|
29
29
|
return 1.0 if value == true
|
|
30
30
|
return 0.0 if value.nil?
|
|
31
|
-
return value.to_f if value.is_a?(String) && numeric_string?(value)
|
|
31
|
+
return value.to_f if value.is_a?(String) && Numericals::Numerify.numeric_string?(value)
|
|
32
32
|
nil
|
|
33
33
|
end
|
|
34
|
+
|
|
35
|
+
# Normalize numeric types for strict equality comparisons (=== semantics).
|
|
36
|
+
def cast(value)
|
|
37
|
+
value.is_a?(Numeric) ? value.to_f : value
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Shared loop for all chain-comparison operators.
|
|
41
|
+
# Yields the compare result for each consecutive pair; block returns true to continue, false to short-circuit.
|
|
42
|
+
# Returns true if all pairs pass, false otherwise. Raises on :nan or invalid args.
|
|
43
|
+
def compare_chain(rules, scope_stack)
|
|
44
|
+
operands = Utils::Array.wrap_nil(rules)
|
|
45
|
+
raise Errors::InvalidArguments if operands.length < 2
|
|
46
|
+
|
|
47
|
+
prev = Engine.call(operands[0], scope_stack)
|
|
48
|
+
operands[1..].each do |rule|
|
|
49
|
+
curr = Engine.call(rule, scope_stack)
|
|
50
|
+
result = compare(prev, curr)
|
|
51
|
+
raise Errors::NotANumber if result == :nan
|
|
52
|
+
return false unless yield(result)
|
|
53
|
+
prev = curr
|
|
54
|
+
end
|
|
55
|
+
true
|
|
56
|
+
end
|
|
34
57
|
end
|
|
35
58
|
end
|
|
36
59
|
end
|
|
@@ -15,7 +15,7 @@ module ShinyJsonLogic
|
|
|
15
15
|
|
|
16
16
|
return rule unless OPERATIONS.key?(operation_key)
|
|
17
17
|
|
|
18
|
-
OPERATIONS.fetch(operation_key).
|
|
18
|
+
OPERATIONS.fetch(operation_key).call(args, scope_stack)
|
|
19
19
|
elsif rule.is_a?(Array)
|
|
20
20
|
rule.map { |val| call(val, scope_stack) }
|
|
21
21
|
else
|
|
@@ -5,29 +5,24 @@ require "shiny_json_logic/errors/invalid_arguments"
|
|
|
5
5
|
module ShinyJsonLogic
|
|
6
6
|
module Numericals
|
|
7
7
|
module MinMaxCollection
|
|
8
|
-
|
|
8
|
+
module_function
|
|
9
9
|
|
|
10
|
-
def collect_numeric_values
|
|
11
|
-
values = collect_values
|
|
10
|
+
def collect_numeric_values(rules, scope_stack)
|
|
11
|
+
values = collect_values(rules, scope_stack)
|
|
12
12
|
raise Errors::InvalidArguments if values.empty?
|
|
13
13
|
raise Errors::InvalidArguments unless values.all? { |v| v.is_a?(Numeric) }
|
|
14
14
|
values
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
-
def collect_values
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
evaluated = evaluate(rules)
|
|
22
|
-
return wrap_nil(evaluated)
|
|
17
|
+
def collect_values(rules, scope_stack)
|
|
18
|
+
if Operations::Base.op?(rules)
|
|
19
|
+
evaluated = Engine.call(rules, scope_stack)
|
|
20
|
+
return Utils::Array.wrap_nil(evaluated)
|
|
23
21
|
end
|
|
24
22
|
|
|
25
|
-
# Otherwise, rules is an array of arguments - evaluate each without expanding
|
|
26
|
-
# e.g., {"max": [1, 2, 3]} or {"max": [1, {"val": "x"}]}
|
|
27
|
-
# Note: {"max": [{"val": "data"}]} where data is [1,2,3] -> invalid (array is one element)
|
|
28
23
|
result = []
|
|
29
|
-
wrap_nil(rules).each do |rule|
|
|
30
|
-
result <<
|
|
24
|
+
Utils::Array.wrap_nil(rules).each do |rule|
|
|
25
|
+
result << Engine.call(rule, scope_stack)
|
|
31
26
|
end
|
|
32
27
|
result
|
|
33
28
|
end
|
|
@@ -3,7 +3,11 @@
|
|
|
3
3
|
module ShinyJsonLogic
|
|
4
4
|
module Numericals
|
|
5
5
|
module Numerify
|
|
6
|
-
|
|
6
|
+
# Regex to match valid numeric strings (integers, floats, scientific notation)
|
|
7
|
+
# Examples: "123", "-45.67", "+3.14", "1e10", "2.5E-3", ".5", "-.5"
|
|
8
|
+
NUMERIC_REGEX = /\A[+-]?(?:\d+\.?\d*|\d*\.?\d+)(?:[eE][+-]?\d+)?\z/
|
|
9
|
+
|
|
10
|
+
module_function
|
|
7
11
|
|
|
8
12
|
def numerify(value)
|
|
9
13
|
return value.to_f if value.is_a?(Numeric)
|
|
@@ -16,10 +20,6 @@ module ShinyJsonLogic
|
|
|
16
20
|
raise TypeError, "Cannot convert #{value.inspect} to a number"
|
|
17
21
|
end
|
|
18
22
|
|
|
19
|
-
# Regex to match valid numeric strings (integers, floats, scientific notation)
|
|
20
|
-
# Examples: "123", "-45.67", "+3.14", "1e10", "2.5E-3", ".5", "-.5"
|
|
21
|
-
NUMERIC_REGEX = /\A[+-]?(?:\d+\.?\d*|\d*\.?\d+)(?:[eE][+-]?\d+)?\z/
|
|
22
|
-
|
|
23
23
|
def numeric_string?(value)
|
|
24
24
|
NUMERIC_REGEX.match?(value)
|
|
25
25
|
end
|
|
@@ -7,6 +7,8 @@ require "shiny_json_logic/errors/invalid_arguments"
|
|
|
7
7
|
module ShinyJsonLogic
|
|
8
8
|
module Numericals
|
|
9
9
|
module WithErrorHandling
|
|
10
|
+
module_function
|
|
11
|
+
|
|
10
12
|
def safe_arithmetic(&block)
|
|
11
13
|
result = yield
|
|
12
14
|
if result.to_f.nan? || result == Float::INFINITY || result == -Float::INFINITY
|
|
@@ -7,36 +7,18 @@ require "shiny_json_logic/numericals/numerify"
|
|
|
7
7
|
module ShinyJsonLogic
|
|
8
8
|
module Operations
|
|
9
9
|
class Addition < Base
|
|
10
|
-
|
|
11
|
-
include Numericals::Numerify
|
|
10
|
+
extend Numericals::WithErrorHandling
|
|
12
11
|
|
|
13
|
-
def
|
|
12
|
+
def self.execute(rules, scope_stack)
|
|
14
13
|
safe_arithmetic do
|
|
15
14
|
result = 0.0
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
count += 1
|
|
20
|
-
result = result + num
|
|
15
|
+
Utils::Array.wrap_nil(rules).each do |rule|
|
|
16
|
+
val = Numericals::Numerify.numerify(evaluate(rule, scope_stack))
|
|
17
|
+
result += val.nil? ? 0 : val
|
|
21
18
|
end
|
|
22
|
-
|
|
23
19
|
result
|
|
24
20
|
end
|
|
25
21
|
end
|
|
26
|
-
|
|
27
|
-
private
|
|
28
|
-
|
|
29
|
-
def each_operand
|
|
30
|
-
wrap_nil(rules).each do |rule|
|
|
31
|
-
yield numerify(evaluate(rule))
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def numerify(value)
|
|
36
|
-
val = super
|
|
37
|
-
return 0 if val.nil?
|
|
38
|
-
val
|
|
39
|
-
end
|
|
40
22
|
end
|
|
41
23
|
end
|
|
42
24
|
end
|
|
@@ -7,17 +7,16 @@ require "shiny_json_logic/numericals/with_error_handling"
|
|
|
7
7
|
module ShinyJsonLogic
|
|
8
8
|
module Operations
|
|
9
9
|
class And < Base
|
|
10
|
-
|
|
10
|
+
extend Numericals::WithErrorHandling
|
|
11
11
|
raise_on_dynamic_args!
|
|
12
12
|
|
|
13
|
-
def
|
|
14
|
-
return handle_invalid_args if dynamic_args?
|
|
13
|
+
def self.execute(rules, scope_stack)
|
|
15
14
|
return handle_invalid_args unless rules.is_a?(Array)
|
|
16
15
|
return false if rules.empty?
|
|
17
16
|
|
|
18
17
|
result = nil
|
|
19
18
|
rules.each do |rule|
|
|
20
|
-
result = evaluate(rule)
|
|
19
|
+
result = evaluate(rule, scope_stack)
|
|
21
20
|
return result unless Truthy.call(result)
|
|
22
21
|
end
|
|
23
22
|
result
|
|
@@ -6,34 +6,21 @@ require "shiny_json_logic/utils/array"
|
|
|
6
6
|
module ShinyJsonLogic
|
|
7
7
|
module Operations
|
|
8
8
|
class Base
|
|
9
|
-
|
|
9
|
+
extend Utils::Array
|
|
10
10
|
|
|
11
|
-
def
|
|
12
|
-
|
|
13
|
-
@dynamic_args = operation?(rules)
|
|
14
|
-
@rules = pre_process(rules)
|
|
11
|
+
def self.call(rules, scope_stack)
|
|
12
|
+
execute(resolve_rules(rules, scope_stack), scope_stack)
|
|
15
13
|
end
|
|
16
14
|
|
|
17
|
-
def
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
attr_reader :scope_stack
|
|
24
|
-
attr_accessor :rules
|
|
25
|
-
|
|
26
|
-
# Access current data through scope_stack
|
|
27
|
-
def data
|
|
28
|
-
scope_stack.current
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def evaluate(rule)
|
|
32
|
-
Engine.call(rule, scope_stack)
|
|
15
|
+
def self.resolve_rules(rules, scope_stack)
|
|
16
|
+
dynamic = op?(rules)
|
|
17
|
+
rules = Engine.call(rules, scope_stack) if dynamic
|
|
18
|
+
raise Errors::InvalidArguments if dynamic && raise_on_dynamic_args?
|
|
19
|
+
rules
|
|
33
20
|
end
|
|
34
21
|
|
|
35
|
-
def
|
|
36
|
-
|
|
22
|
+
def self.execute(_rules, _scope_stack)
|
|
23
|
+
raise NotImplementedError
|
|
37
24
|
end
|
|
38
25
|
|
|
39
26
|
def self.raise_on_dynamic_args!
|
|
@@ -44,17 +31,12 @@ module ShinyJsonLogic
|
|
|
44
31
|
@raise_on_dynamic_args
|
|
45
32
|
end
|
|
46
33
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
def pre_process(rules)
|
|
50
|
-
return evaluate(rules) if operation?(rules)
|
|
51
|
-
|
|
52
|
-
rules
|
|
34
|
+
def self.evaluate(rule, scope_stack)
|
|
35
|
+
Engine.call(rule, scope_stack)
|
|
53
36
|
end
|
|
54
37
|
|
|
55
|
-
def
|
|
38
|
+
def self.op?(value)
|
|
56
39
|
return false unless value.is_a?(Hash) && !value.empty?
|
|
57
|
-
|
|
58
40
|
OperatorSolver.operation?(value)
|
|
59
41
|
end
|
|
60
42
|
end
|
|
@@ -5,9 +5,9 @@ require "shiny_json_logic/operations/base"
|
|
|
5
5
|
module ShinyJsonLogic
|
|
6
6
|
module Operations
|
|
7
7
|
class Coalesce < Base
|
|
8
|
-
def
|
|
8
|
+
def self.execute(rules, scope_stack)
|
|
9
9
|
rules.each do |rule|
|
|
10
|
-
result = evaluate(rule)
|
|
10
|
+
result = evaluate(rule, scope_stack)
|
|
11
11
|
return result unless result.nil?
|
|
12
12
|
end
|
|
13
13
|
nil
|
|
@@ -5,11 +5,11 @@ require "shiny_json_logic/operations/base"
|
|
|
5
5
|
module ShinyJsonLogic
|
|
6
6
|
module Operations
|
|
7
7
|
class Concatenation < Base
|
|
8
|
-
def
|
|
8
|
+
def self.execute(rules, scope_stack)
|
|
9
9
|
result = []
|
|
10
|
-
wrap_nil(rules).each do |rule|
|
|
11
|
-
evaluated = evaluate(rule)
|
|
12
|
-
wrap_nil(evaluated).each { |v| result << v.to_s }
|
|
10
|
+
Utils::Array.wrap_nil(rules).each do |rule|
|
|
11
|
+
evaluated = evaluate(rule, scope_stack)
|
|
12
|
+
Utils::Array.wrap_nil(evaluated).each { |v| result << v.to_s }
|
|
13
13
|
end
|
|
14
14
|
result.join
|
|
15
15
|
end
|
|
@@ -1,30 +1,15 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "shiny_json_logic/operations/base"
|
|
4
|
-
require "shiny_json_logic/numericals/with_error_handling"
|
|
5
4
|
require "shiny_json_logic/comparisons/comparable"
|
|
6
5
|
|
|
7
6
|
module ShinyJsonLogic
|
|
8
7
|
module Operations
|
|
9
8
|
class Different < Base
|
|
10
|
-
include Numericals::WithErrorHandling
|
|
11
|
-
include Comparisons::Comparable
|
|
12
9
|
raise_on_dynamic_args!
|
|
13
10
|
|
|
14
|
-
def
|
|
15
|
-
|
|
16
|
-
operands = wrap_nil(rules)
|
|
17
|
-
return handle_invalid_args if operands.length < 2
|
|
18
|
-
|
|
19
|
-
prev = evaluate(operands[0])
|
|
20
|
-
operands[1..].each do |rule|
|
|
21
|
-
curr = evaluate(rule)
|
|
22
|
-
result = compare(prev, curr)
|
|
23
|
-
return handle_nan if result == :nan
|
|
24
|
-
return false if result == 0
|
|
25
|
-
prev = curr
|
|
26
|
-
end
|
|
27
|
-
true
|
|
11
|
+
def self.execute(rules, scope_stack)
|
|
12
|
+
Comparisons::Comparable.compare_chain(rules, scope_stack) { |r| r != 0 }
|
|
28
13
|
end
|
|
29
14
|
end
|
|
30
15
|
end
|
|
@@ -7,18 +7,19 @@ require "shiny_json_logic/numericals/numerify"
|
|
|
7
7
|
module ShinyJsonLogic
|
|
8
8
|
module Operations
|
|
9
9
|
class Division < Base
|
|
10
|
-
|
|
11
|
-
include Numericals::Numerify
|
|
10
|
+
extend Numericals::WithErrorHandling
|
|
12
11
|
|
|
13
|
-
def
|
|
14
|
-
operands = wrap_nil(rules)
|
|
12
|
+
def self.execute(rules, scope_stack)
|
|
13
|
+
operands = Utils::Array.wrap_nil(rules)
|
|
15
14
|
return handle_invalid_args if operands.empty?
|
|
16
15
|
|
|
17
16
|
result = nil
|
|
18
17
|
count = 0
|
|
19
18
|
|
|
20
19
|
begin
|
|
21
|
-
|
|
20
|
+
operands.each do |rule|
|
|
21
|
+
evaluated = evaluate(rule, scope_stack)
|
|
22
|
+
num = Numericals::Numerify.numerify(evaluated)
|
|
22
23
|
return handle_nan if num.nil?
|
|
23
24
|
count += 1
|
|
24
25
|
result = result.nil? ? num : result / num
|
|
@@ -33,15 +34,6 @@ module ShinyJsonLogic
|
|
|
33
34
|
|
|
34
35
|
safe_arithmetic { final_result }
|
|
35
36
|
end
|
|
36
|
-
|
|
37
|
-
private
|
|
38
|
-
|
|
39
|
-
def each_operand(operands)
|
|
40
|
-
operands.each do |rule|
|
|
41
|
-
evaluated = evaluate(rule)
|
|
42
|
-
yield numerify(evaluated)
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
37
|
end
|
|
46
38
|
end
|
|
47
39
|
end
|
|
@@ -6,9 +6,9 @@ require "shiny_json_logic/truthy"
|
|
|
6
6
|
module ShinyJsonLogic
|
|
7
7
|
module Operations
|
|
8
8
|
class DoubleNot < Base
|
|
9
|
-
def
|
|
10
|
-
value = wrap_nil(rules).first
|
|
11
|
-
!!Truthy.call(evaluate(value))
|
|
9
|
+
def self.execute(rules, scope_stack)
|
|
10
|
+
value = Utils::Array.wrap_nil(rules).first
|
|
11
|
+
!!Truthy.call(evaluate(value, scope_stack))
|
|
12
12
|
end
|
|
13
13
|
end
|
|
14
14
|
end
|
|
@@ -1,29 +1,15 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "shiny_json_logic/operations/base"
|
|
4
|
-
require "shiny_json_logic/numericals/with_error_handling"
|
|
5
4
|
require "shiny_json_logic/comparisons/comparable"
|
|
6
5
|
|
|
7
6
|
module ShinyJsonLogic
|
|
8
7
|
module Operations
|
|
9
8
|
class Equal < Base
|
|
10
|
-
include Numericals::WithErrorHandling
|
|
11
|
-
include Comparisons::Comparable
|
|
12
9
|
raise_on_dynamic_args!
|
|
13
10
|
|
|
14
|
-
def
|
|
15
|
-
|
|
16
|
-
operands = wrap_nil(rules)
|
|
17
|
-
return handle_invalid_args if operands.length < 2
|
|
18
|
-
|
|
19
|
-
first = evaluate(operands[0])
|
|
20
|
-
operands[1..].each do |rule|
|
|
21
|
-
curr = evaluate(rule)
|
|
22
|
-
result = compare(first, curr)
|
|
23
|
-
return handle_nan if result == :nan
|
|
24
|
-
return false unless result == 0
|
|
25
|
-
end
|
|
26
|
-
true
|
|
11
|
+
def self.execute(rules, scope_stack)
|
|
12
|
+
Comparisons::Comparable.compare_chain(rules, scope_stack) { |r| r == 0 }
|
|
27
13
|
end
|
|
28
14
|
end
|
|
29
15
|
end
|
|
@@ -5,11 +5,11 @@ require "shiny_json_logic/operations/base"
|
|
|
5
5
|
module ShinyJsonLogic
|
|
6
6
|
module Operations
|
|
7
7
|
class Exists < Base
|
|
8
|
-
def
|
|
9
|
-
current =
|
|
8
|
+
def self.execute(rules, scope_stack)
|
|
9
|
+
current = scope_stack.current
|
|
10
10
|
|
|
11
|
-
wrap_nil(rules).each do |rule|
|
|
12
|
-
segment = evaluate(rule)
|
|
11
|
+
Utils::Array.wrap_nil(rules).each do |rule|
|
|
12
|
+
segment = evaluate(rule, scope_stack)
|
|
13
13
|
return false unless current.key?(segment)
|
|
14
14
|
current = current[segment]
|
|
15
15
|
end
|
|
@@ -9,13 +9,11 @@ module ShinyJsonLogic
|
|
|
9
9
|
raise_on_nil_filter!
|
|
10
10
|
raise_on_dynamic_args!
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
def on_each(item)
|
|
12
|
+
def self.on_each(item, filter, scope_stack)
|
|
15
13
|
Truthy.call(Engine.call(filter, scope_stack)) ? item : nil
|
|
16
14
|
end
|
|
17
15
|
|
|
18
|
-
def on_after(results)
|
|
16
|
+
def self.on_after(results, _scope_stack)
|
|
19
17
|
results.compact
|
|
20
18
|
end
|
|
21
19
|
end
|
|
@@ -1,30 +1,15 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "shiny_json_logic/operations/base"
|
|
4
|
-
require "shiny_json_logic/numericals/with_error_handling"
|
|
5
4
|
require "shiny_json_logic/comparisons/comparable"
|
|
6
5
|
|
|
7
6
|
module ShinyJsonLogic
|
|
8
7
|
module Operations
|
|
9
8
|
class Greater < Base
|
|
10
|
-
include Numericals::WithErrorHandling
|
|
11
|
-
include Comparisons::Comparable
|
|
12
9
|
raise_on_dynamic_args!
|
|
13
10
|
|
|
14
|
-
def
|
|
15
|
-
|
|
16
|
-
operands = wrap_nil(rules)
|
|
17
|
-
return handle_invalid_args if operands.length < 2
|
|
18
|
-
|
|
19
|
-
prev = evaluate(operands[0])
|
|
20
|
-
operands[1..].each do |rule|
|
|
21
|
-
curr = evaluate(rule)
|
|
22
|
-
result = compare(prev, curr)
|
|
23
|
-
return handle_nan if result == :nan
|
|
24
|
-
return false unless result == 1
|
|
25
|
-
prev = curr
|
|
26
|
-
end
|
|
27
|
-
true
|
|
11
|
+
def self.execute(rules, scope_stack)
|
|
12
|
+
Comparisons::Comparable.compare_chain(rules, scope_stack) { |r| r == 1 }
|
|
28
13
|
end
|
|
29
14
|
end
|
|
30
15
|
end
|
|
@@ -1,30 +1,15 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "shiny_json_logic/operations/base"
|
|
4
|
-
require "shiny_json_logic/numericals/with_error_handling"
|
|
5
4
|
require "shiny_json_logic/comparisons/comparable"
|
|
6
5
|
|
|
7
6
|
module ShinyJsonLogic
|
|
8
7
|
module Operations
|
|
9
8
|
class GreaterEqual < Base
|
|
10
|
-
include Numericals::WithErrorHandling
|
|
11
|
-
include Comparisons::Comparable
|
|
12
9
|
raise_on_dynamic_args!
|
|
13
10
|
|
|
14
|
-
def
|
|
15
|
-
|
|
16
|
-
operands = wrap_nil(rules)
|
|
17
|
-
return handle_invalid_args if operands.length < 2
|
|
18
|
-
|
|
19
|
-
prev = evaluate(operands[0])
|
|
20
|
-
operands[1..].each do |rule|
|
|
21
|
-
curr = evaluate(rule)
|
|
22
|
-
result = compare(prev, curr)
|
|
23
|
-
return handle_nan if result == :nan
|
|
24
|
-
return false unless result >= 0
|
|
25
|
-
prev = curr
|
|
26
|
-
end
|
|
27
|
-
true
|
|
11
|
+
def self.execute(rules, scope_stack)
|
|
12
|
+
Comparisons::Comparable.compare_chain(rules, scope_stack) { |r| r >= 0 }
|
|
28
13
|
end
|
|
29
14
|
end
|
|
30
15
|
end
|
|
@@ -7,34 +7,23 @@ require "shiny_json_logic/numericals/with_error_handling"
|
|
|
7
7
|
module ShinyJsonLogic
|
|
8
8
|
module Operations
|
|
9
9
|
class If < Base
|
|
10
|
-
|
|
10
|
+
extend Numericals::WithErrorHandling
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
@rules = rules
|
|
15
|
-
@scope_stack = scope_stack
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def call
|
|
12
|
+
def self.call(rules, scope_stack)
|
|
13
|
+
# Skip pre_process - spec requires static array, dynamic args should error
|
|
19
14
|
return handle_invalid_args unless rules.is_a?(Array)
|
|
20
15
|
|
|
21
16
|
rules.each_slice(2) do |condition_rule, value_rule|
|
|
22
|
-
condition_result =
|
|
17
|
+
condition_result = Engine.call(condition_rule, scope_stack)
|
|
23
18
|
return condition_result if value_rule.nil?
|
|
24
19
|
|
|
25
20
|
next unless Truthy.call(condition_result)
|
|
26
21
|
|
|
27
|
-
return
|
|
22
|
+
return Engine.call(value_rule, scope_stack)
|
|
28
23
|
end
|
|
29
24
|
|
|
30
25
|
nil
|
|
31
26
|
end
|
|
32
|
-
|
|
33
|
-
private
|
|
34
|
-
|
|
35
|
-
def evaluate(rule)
|
|
36
|
-
Engine.call(rule, scope_stack)
|
|
37
|
-
end
|
|
38
27
|
end
|
|
39
28
|
end
|
|
40
29
|
end
|
|
@@ -5,9 +5,9 @@ require "shiny_json_logic/operations/base"
|
|
|
5
5
|
module ShinyJsonLogic
|
|
6
6
|
module Operations
|
|
7
7
|
class Inclusion < Base
|
|
8
|
-
def
|
|
9
|
-
needle = evaluate(rules.first)
|
|
10
|
-
haystack = evaluate(rules.last)
|
|
8
|
+
def self.execute(rules, scope_stack)
|
|
9
|
+
needle = evaluate(rules.first, scope_stack)
|
|
10
|
+
haystack = evaluate(rules.last, scope_stack)
|
|
11
11
|
haystack.include?(needle)
|
|
12
12
|
end
|
|
13
13
|
end
|