json-logic-rb 0.1.5 → 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.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +197 -197
  3. data/lib/json_logic/engine.rb +22 -21
  4. data/lib/json_logic/enumerable_operation.rb +27 -5
  5. data/lib/json_logic/errors/error.rb +29 -0
  6. data/lib/json_logic/errors/invalid_arguments_error.rb +7 -0
  7. data/lib/json_logic/errors/logic_error.rb +7 -0
  8. data/lib/json_logic/errors/nan_error.rb +7 -0
  9. data/lib/json_logic/ext/array.rb +5 -0
  10. data/lib/json_logic/operations/add.rb +3 -3
  11. data/lib/json_logic/operations/all.rb +3 -6
  12. data/lib/json_logic/operations/and.rb +6 -5
  13. data/lib/json_logic/operations/bool_cast.rb +2 -3
  14. data/lib/json_logic/operations/cat.rb +3 -1
  15. data/lib/json_logic/operations/coalesce.rb +9 -0
  16. data/lib/json_logic/operations/div.rb +7 -1
  17. data/lib/json_logic/operations/equal.rb +12 -3
  18. data/lib/json_logic/operations/exists.rb +14 -0
  19. data/lib/json_logic/operations/filter.rb +11 -3
  20. data/lib/json_logic/operations/gt.rb +12 -4
  21. data/lib/json_logic/operations/gte.rb +12 -4
  22. data/lib/json_logic/operations/if.rb +2 -0
  23. data/lib/json_logic/operations/in.rb +2 -0
  24. data/lib/json_logic/operations/lt.rb +10 -4
  25. data/lib/json_logic/operations/lte.rb +12 -4
  26. data/lib/json_logic/operations/map.rb +14 -2
  27. data/lib/json_logic/operations/max.rb +3 -1
  28. data/lib/json_logic/operations/merge.rb +4 -3
  29. data/lib/json_logic/operations/min.rb +3 -1
  30. data/lib/json_logic/operations/missing.rb +4 -26
  31. data/lib/json_logic/operations/missing_some.rb +6 -20
  32. data/lib/json_logic/operations/mod.rb +9 -1
  33. data/lib/json_logic/operations/mul.rb +4 -1
  34. data/lib/json_logic/operations/none.rb +4 -5
  35. data/lib/json_logic/operations/not_equal.rb +12 -3
  36. data/lib/json_logic/operations/or.rb +5 -1
  37. data/lib/json_logic/operations/preserve.rb +9 -0
  38. data/lib/json_logic/operations/reduce.rb +21 -5
  39. data/lib/json_logic/operations/some.rb +4 -7
  40. data/lib/json_logic/operations/strict_equal.rb +26 -3
  41. data/lib/json_logic/operations/strict_not_equal.rb +24 -3
  42. data/lib/json_logic/operations/sub.rb +8 -1
  43. data/lib/json_logic/operations/substr.rb +12 -20
  44. data/lib/json_logic/operations/ternary.rb +1 -7
  45. data/lib/json_logic/operations/throw.rb +12 -0
  46. data/lib/json_logic/operations/try.rb +35 -0
  47. data/lib/json_logic/operations/val.rb +79 -0
  48. data/lib/json_logic/operations/var.rb +22 -20
  49. data/lib/json_logic/scope.rb +67 -0
  50. data/lib/json_logic/semantics.rb +107 -38
  51. data/lib/json_logic/tree.rb +97 -0
  52. data/lib/json_logic/version.rb +1 -1
  53. data/lib/json_logic.rb +12 -0
  54. data/script/build_tests_json.rb +26 -0
  55. data/script/compliance.rb +160 -37
  56. data/spec/tmp/v2/tests.json +16981 -0
  57. metadata +24 -13
  58. /data/spec/tmp/{tests.json → v1/tests.json} +0 -0
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JsonLogic
4
+ class LogicError < Error
5
+ DEFAULT_MESSAGE = "LogicError"
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JsonLogic
4
+ class NaNError < Error
5
+ DEFAULT_MESSAGE = "NaN"
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Array
4
+ def self.wrap(value) = value.is_a?(Array) ? value : [value]
5
+ end
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ using JsonLogic::Semantics
4
+
3
5
  class JsonLogic::Operations::Add < JsonLogic::Operation
4
6
  def self.name = "+"
5
7
 
6
- def call(values, _data)
7
- values.map!(&:to_f).sum
8
- end
8
+ def call(args, _data) = args.map(&:to_f).sum
9
9
  end
@@ -5,12 +5,9 @@ using JsonLogic::Semantics
5
5
  class JsonLogic::Operations::All < JsonLogic::EnumerableOperation
6
6
  def self.name = "all"
7
7
 
8
- def call(args, data)
9
- items, rule_applied_to_each_item = resolve_items_and_per_item_rule(args, data)
10
- return false if items.empty?
8
+ protected
11
9
 
12
- items.all? do |item|
13
- !!JsonLogic.apply(rule_applied_to_each_item, item)
14
- end
10
+ def call_with_values(values)
11
+ !values.empty? && values.all? { |value| !!value }
15
12
  end
16
13
  end
@@ -6,11 +6,12 @@ class JsonLogic::Operations::And < JsonLogic::LazyOperation
6
6
  def self.name = "and"
7
7
 
8
8
  def call(args, data)
9
- last = nil
10
- args.each do |a|
11
- last = JsonLogic.apply(a, data)
12
- return last unless !!last
9
+ raise JsonLogic::InvalidArgumentsError.new unless args.is_a?(Array)
10
+
11
+ args.reduce(false) do |_memo, rule|
12
+ value = JsonLogic.apply(rule, data)
13
+ break value unless value.to_bool
14
+ value
13
15
  end
14
- last
15
16
  end
16
17
  end
@@ -1,10 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  using JsonLogic::Semantics
4
+
4
5
  class JsonLogic::Operations::BoolCast < JsonLogic::Operation
5
6
  def self.name = "!!"
6
7
 
7
- def call((a), _data)
8
- !!a
9
- end
8
+ def call((a), _data) = !!a
10
9
  end
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ using JsonLogic::Semantics
4
+
3
5
  class JsonLogic::Operations::Cat < JsonLogic::Operation
4
6
  def self.name = "cat"
5
7
 
6
- def call(values, _data) = values.map!(&:to_s).join
8
+ def call(args, _data) = args.map!(&:to_s).join
7
9
  end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ using JsonLogic::Semantics
4
+
5
+ class JsonLogic::Operations::Coalesce < JsonLogic::Operation
6
+ def self.name = "??"
7
+
8
+ def call(args, _data) = args.find { |v| !v.nil? }
9
+ end
@@ -1,7 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ using JsonLogic::Semantics
4
+
3
5
  class JsonLogic::Operations::Div < JsonLogic::Operation
4
6
  def self.name = "/"
5
7
 
6
- def call((a,b), _data) = (b.to_f == 0 ? nil : a.to_f / b.to_f)
8
+ def call(args, _data)
9
+ raise JsonLogic::InvalidArgumentsError.new if args.empty?
10
+ numbers = args.map(&:to_f)
11
+ numbers.one? ? (1.0 / numbers.first) : numbers.drop(1).reduce(numbers.first, :/)
12
+ end
7
13
  end
@@ -2,10 +2,19 @@
2
2
 
3
3
  using JsonLogic::Semantics
4
4
 
5
- class JsonLogic::Operations::Equal < JsonLogic::Operation
5
+ class JsonLogic::Operations::Equal < JsonLogic::LazyOperation
6
6
  def self.name = "=="
7
7
 
8
- def call((a,b), _data)
9
- a == b
8
+ def call(args, data)
9
+ raise JsonLogic::InvalidArgumentsError.new unless args.is_a?(Array) && args.size >= 2
10
+
11
+ prev = JsonLogic.apply(args.first, data)
12
+ args[1..].each do |arg|
13
+ current = JsonLogic.apply(arg, data)
14
+ return false unless prev == current
15
+
16
+ prev = current
17
+ end
18
+ true
10
19
  end
11
20
  end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ using JsonLogic::Semantics
4
+
5
+ class JsonLogic::Operations::Exists < JsonLogic::Operation
6
+ def self.name = "exists"
7
+ def self.values_only? = false
8
+
9
+ def call(args, data) = JsonLogic::Tree.new(data).exists?(normalize_path(args, data), split_dots: false)
10
+
11
+ private
12
+
13
+ def normalize_path(args, data) = args.is_a?(Array) ? Array.wrap(args).map { |part| JsonLogic.apply(part, data) } : JsonLogic.apply(args, data)
14
+ end
@@ -6,10 +6,18 @@ class JsonLogic::Operations::Filter < JsonLogic::EnumerableOperation
6
6
  def self.name = "filter"
7
7
 
8
8
  def call(args, data)
9
- items, rule_applied_to_each_item = resolve_items_and_per_item_rule(args, data)
9
+ raise JsonLogic::InvalidArgumentsError.new if args.is_a?(Array) && args.size >= 2 && args[1].nil?
10
+ raise JsonLogic::InvalidArgumentsError.new unless args.is_a?(Array) && args.size >= 2
11
+ raise JsonLogic::InvalidArgumentsError.new if args[0].nil?
10
12
 
11
- items.filter do |item|
12
- !!JsonLogic.apply(rule_applied_to_each_item, item)
13
+ items_rule, rule = args
14
+ items = Array(JsonLogic.apply(items_rule, data))
15
+
16
+ return [] if rule.nil?
17
+
18
+ items.each_with_index.each_with_object([]) do |(item, index), filtered|
19
+ value = JsonLogic.apply(rule, JsonLogic::Scope.new(item, data, index))
20
+ filtered << item if value.to_bool
13
21
  end
14
22
  end
15
23
  end
@@ -2,11 +2,19 @@
2
2
 
3
3
  using JsonLogic::Semantics
4
4
 
5
- class JsonLogic::Operations::GT < JsonLogic::Operation
5
+ class JsonLogic::Operations::GT < JsonLogic::LazyOperation
6
6
  def self.name = ">"
7
7
 
8
- def call(values, _data)
9
- return values[0] > values[1] if values.size == 2
10
- values.each_cons(2).all? { |a,b| a > b }
8
+ def call(args, data)
9
+ raise JsonLogic::InvalidArgumentsError.new unless args.is_a?(Array) && args.size >= 2
10
+
11
+ previous = JsonLogic.apply(args.first, data)
12
+ args.drop(1).all? do |rule|
13
+ current = JsonLogic.apply(rule, data)
14
+ next false unless previous > current
15
+
16
+ previous = current
17
+ true
18
+ end
11
19
  end
12
20
  end
@@ -2,11 +2,19 @@
2
2
 
3
3
  using JsonLogic::Semantics
4
4
 
5
- class JsonLogic::Operations::GTE < JsonLogic::Operation
5
+ class JsonLogic::Operations::GTE < JsonLogic::LazyOperation
6
6
  def self.name = ">="
7
7
 
8
- def call(values, _data)
9
- return values[0] >= values[1] if values.size == 2
10
- values.each_cons(2).all? { |a,b| a >= b }
8
+ def call(args, data)
9
+ raise JsonLogic::InvalidArgumentsError.new unless args.is_a?(Array) && args.size >= 2
10
+
11
+ previous = JsonLogic.apply(args.first, data)
12
+ args.drop(1).all? do |rule|
13
+ current = JsonLogic.apply(rule, data)
14
+ next false unless previous >= current
15
+
16
+ previous = current
17
+ true
18
+ end
11
19
  end
12
20
  end
@@ -6,6 +6,8 @@ class JsonLogic::Operations::If < JsonLogic::LazyOperation
6
6
  def self.name = "if"
7
7
 
8
8
  def call(args, data)
9
+ raise JsonLogic::InvalidArgumentsError.new unless args.is_a?(Array)
10
+
9
11
  i = 0
10
12
  while i < args.size - 1
11
13
  return JsonLogic.apply(args[i + 1], data) if !!(JsonLogic.apply(args[i], data))
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ using JsonLogic::Semantics
4
+
3
5
  class JsonLogic::Operations::In < JsonLogic::Operation
4
6
  def self.name = "in"
5
7
 
@@ -2,11 +2,17 @@
2
2
 
3
3
  using JsonLogic::Semantics
4
4
 
5
- class JsonLogic::Operations::LT < JsonLogic::Operation
5
+ class JsonLogic::Operations::LT < JsonLogic::LazyOperation
6
6
  def self.name = "<"
7
7
 
8
- def call(values, _data)
9
- return values[0] < values[1] if values.size == 2
10
- values.each_cons(2).all? { |a,b| a < b }
8
+ def call(args, data)
9
+ raise JsonLogic::InvalidArgumentsError.new unless args.is_a?(Array) && args.size >= 2
10
+
11
+ args.drop(1).reduce(JsonLogic.apply(args.first, data)) do |previous, rule|
12
+ current = JsonLogic.apply(rule, data)
13
+ return false unless previous < current
14
+ current
15
+ end
16
+ true
11
17
  end
12
18
  end
@@ -2,11 +2,19 @@
2
2
 
3
3
  using JsonLogic::Semantics
4
4
 
5
- class JsonLogic::Operations::LTE < JsonLogic::Operation
5
+ class JsonLogic::Operations::LTE < JsonLogic::LazyOperation
6
6
  def self.name = "<="
7
7
 
8
- def call(values, _data)
9
- return values[0] <= values[1] if values.size == 2
10
- values.each_cons(2).all? { |a,b| a <= b }
8
+ def call(args, data)
9
+ raise JsonLogic::InvalidArgumentsError.new unless args.is_a?(Array) && args.size >= 2
10
+
11
+ previous = JsonLogic.apply(args.first, data)
12
+ args.drop(1).all? do |rule|
13
+ current = JsonLogic.apply(rule, data)
14
+ next false unless previous <= current
15
+
16
+ previous = current
17
+ true
18
+ end
11
19
  end
12
20
  end
@@ -1,10 +1,22 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ using JsonLogic::Semantics
4
+
3
5
  class JsonLogic::Operations::Map < JsonLogic::EnumerableOperation
4
6
  def self.name = "map"
5
7
 
6
8
  def call(args, data)
7
- items, rule_applied_to_each_item = resolve_items_and_per_item_rule(args, data)
8
- items.map { |item| JsonLogic.apply(rule_applied_to_each_item, item) }
9
+ raise JsonLogic::InvalidArgumentsError.new if args.is_a?(Array) && args.size >= 2 && args[1].nil?
10
+ raise JsonLogic::InvalidArgumentsError.new unless args.is_a?(Array) && args.size >= 2
11
+ raise JsonLogic::InvalidArgumentsError.new if args[0].nil?
12
+
13
+ items_rule, rule = args
14
+ items = Array(JsonLogic.apply(items_rule, data))
15
+
16
+ return [] if rule.nil?
17
+
18
+ items.each_with_index.map do |item, index|
19
+ JsonLogic.apply(rule, JsonLogic::Scope.new(item, data, index))
20
+ end
9
21
  end
10
22
  end
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ using JsonLogic::Semantics
4
+
3
5
  class JsonLogic::Operations::Max < JsonLogic::Operation
4
6
  def self.name = "max"
5
7
 
6
- def call(values, _data) = values.max
8
+ def call(args, _data) = args.max
7
9
  end
@@ -1,8 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ using JsonLogic::Semantics
4
+
3
5
  class JsonLogic::Operations::Merge < JsonLogic::Operation
4
6
  def self.name = "merge"
5
- def call(values, _data)
6
- values.flat_map { |v| v.is_a?(Array) ? v : [v] }
7
- end
7
+
8
+ def call(args, _data) = args.flat_map { |v| v.is_a?(Array) ? v : [v] }
8
9
  end
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ using JsonLogic::Semantics
4
+
3
5
  class JsonLogic::Operations::Min < JsonLogic::Operation
4
6
  def self.name = "min"
5
7
 
6
- def call(values, _data) = values.min
8
+ def call(args, _data) = args.min
7
9
  end
@@ -1,33 +1,11 @@
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
 
6
- def call(values, data)
7
- keys =
8
- if values.size == 1 && values.first.is_a?(Array)
9
- values.first
10
- else
11
- values
12
- end
13
-
14
- keys.select { |k| dig(data, k).nil? }
15
- end
16
-
17
- private
18
-
19
- def dig(obj, path)
20
- return nil if obj.nil?
21
- cur = obj
22
- path.to_s.split(".").each do |k|
23
- if cur.is_a?(Array) && k =~ /\A\d+\z/
24
- cur = cur[k.to_i]
25
- elsif cur.is_a?(Hash)
26
- cur = cur[k] || cur[k.to_s] || cur[k.to_sym]
27
- else
28
- return nil
29
- end
30
- end
31
- cur
8
+ def call(args, data)
9
+ Array.wrap(args).select { |key| JsonLogic::Tree.new(data).dig(key).nil? }
32
10
  end
33
11
  end
@@ -1,28 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ using JsonLogic::Semantics
4
+
3
5
  class JsonLogic::Operations::MissingSome < JsonLogic::Operation
4
6
  def self.name = "missing_some"
5
7
 
6
8
  def call((min_ok, list), data)
7
- arr = list.is_a?(Array) ? list : Array(list)
8
- missing = arr.select { |k| dig(data, k).nil? }
9
- (arr.size - missing.size) >= min_ok ? [] : missing
10
- end
11
-
12
- private
13
-
14
- def dig(obj, path)
15
- return nil if obj.nil?
16
- cur = obj
17
- path.to_s.split(".").each do |k|
18
- if cur.is_a?(Array) && k =~ /\A\d+\z/
19
- cur = cur[k.to_i]
20
- elsif cur.is_a?(Hash)
21
- cur = cur[k] || cur[k.to_s] || cur[k.to_sym]
22
- else
23
- return nil
24
- end
25
- end
26
- cur
9
+ json = JsonLogic::Tree.new(data)
10
+ keys = Array.wrap(list)
11
+ missing = keys.select { |key| json.dig(key).nil? }
12
+ (keys.size - missing.size) >= min_ok ? [] : missing
27
13
  end
28
14
  end
@@ -1,7 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ using JsonLogic::Semantics
4
+
3
5
  class JsonLogic::Operations::Mod < JsonLogic::Operation
4
6
  def self.name = "%"
5
7
 
6
- def call((a,b), _data) = a.to_f % b.to_f
8
+ def call(args, _data)
9
+ raise JsonLogic::InvalidArgumentsError.new if args.size < 2
10
+ numbers = args.map(&:to_f)
11
+ numbers.drop(1).reduce(numbers.first) do |result, divisor|
12
+ result - divisor * (result / divisor).truncate
13
+ end
14
+ end
7
15
  end
@@ -1,6 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ using JsonLogic::Semantics
4
+
3
5
  class JsonLogic::Operations::Mul < JsonLogic::Operation
4
6
  def self.name = "*"
5
- def call(values, _data) = values.map!(&:to_f).inject(1){|m,v| m * v }
7
+
8
+ def call(args, _data) = args.map(&:to_f).reduce(1.0, :*)
6
9
  end
@@ -5,10 +5,9 @@ using JsonLogic::Semantics
5
5
  class JsonLogic::Operations::None < JsonLogic::EnumerableOperation
6
6
  def self.name = "none"
7
7
 
8
- def call(args, data)
9
- items, rule_applied_to_each_item = resolve_items_and_per_item_rule(args, data)
10
- items.none? do |item|
11
- !!(JsonLogic.apply(rule_applied_to_each_item, item))
12
- end
8
+ protected
9
+
10
+ def call_with_values(values)
11
+ values.none? { |value| !!value }
13
12
  end
14
13
  end
@@ -2,10 +2,19 @@
2
2
 
3
3
  using JsonLogic::Semantics
4
4
 
5
- class JsonLogic::Operations::NotEqual < JsonLogic::Operation
5
+ class JsonLogic::Operations::NotEqual < JsonLogic::LazyOperation
6
6
  def self.name = "!="
7
7
 
8
- def call((a,b), _data)
9
- !(a == b)
8
+ def call(args, data)
9
+ raise JsonLogic::InvalidArgumentsError.new unless args.is_a?(Array) && args.size >= 2
10
+
11
+ prev = JsonLogic.apply(args.first, data)
12
+ args[1..].each do |arg|
13
+ current = JsonLogic.apply(arg, data)
14
+ return false if prev == current
15
+
16
+ prev = current
17
+ end
18
+ true
10
19
  end
11
20
  end
@@ -1,15 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  using JsonLogic::Semantics
4
+
4
5
  class JsonLogic::Operations::Or < JsonLogic::LazyOperation
5
6
  def self.name = "or"
6
7
 
7
8
  def call(args, data)
9
+ raise JsonLogic::InvalidArgumentsError.new unless args.is_a?(Array)
10
+ return false if args.empty?
11
+
8
12
  args.each do |a|
9
13
  v = JsonLogic.apply(a, data)
10
14
  return v if !!v
11
15
  end
12
16
 
13
- args.empty? ? nil : JsonLogic.apply(args.last, data)
17
+ JsonLogic.apply(args.last, data)
14
18
  end
15
19
  end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ using JsonLogic::Semantics
4
+
5
+ class JsonLogic::Operations::Preserve < JsonLogic::LazyOperation
6
+ def self.name = "preserve"
7
+
8
+ def call(args, _data) = args.is_a?(Array) ? args : [args]
9
+ end
@@ -1,18 +1,34 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ using JsonLogic::Semantics
4
+
3
5
  class JsonLogic::Operations::Reduce < JsonLogic::EnumerableOperation
4
6
  def self.name = "reduce"
5
7
 
6
8
  def call(args, data)
7
- rule_that_returns_items, step_rule_applied_per_item, rule_that_returns_initial_accumulator = args
9
+ raise JsonLogic::InvalidArgumentsError.new unless args.is_a?(Array) && args.size >= 2
10
+
11
+ rule_that_returns_items = args[0]
12
+ step_rule_applied_per_item = args[1]
13
+ rule_that_returns_initial_accumulator = args[2]
14
+ raise JsonLogic::InvalidArgumentsError.new if step_rule_applied_per_item.nil?
8
15
 
9
- items = Array(JsonLogic.apply(rule_that_returns_items, data))
10
- acc = JsonLogic.apply(rule_that_returns_initial_accumulator, data)
16
+ items_value = JsonLogic.apply(rule_that_returns_items, data)
17
+ items = Array(items_value)
18
+ acc = rule_that_returns_initial_accumulator.nil? ? nil : JsonLogic.apply(rule_that_returns_initial_accumulator, data)
11
19
 
12
- items.reduce(acc) do |memo, item|
20
+ items.each_with_index.reduce(acc) do |memo, (item, idx)|
21
+ base_data = data.is_a?(Hash) ? data : {}
13
22
  JsonLogic.apply(
14
23
  step_rule_applied_per_item,
15
- (data || {}).merge("" => item, "current" => item, "accumulator" => memo)
24
+ base_data.merge(
25
+ "" => item,
26
+ "current" => item,
27
+ "accumulator" => memo,
28
+ "index" => idx,
29
+ "__parent__" => data,
30
+ "__scope__" => true
31
+ )
16
32
  )
17
33
  end
18
34
  end
@@ -1,16 +1,13 @@
1
- # frozen_string_literal: tru
1
+ # frozen_string_literal: true
2
2
 
3
3
  using JsonLogic::Semantics
4
4
 
5
5
  class JsonLogic::Operations::Some < JsonLogic::EnumerableOperation
6
6
  def self.name = "some"
7
7
 
8
- def call(args, data)
9
- items, rule_applied_to_each_item = resolve_items_and_per_item_rule(args, data)
10
- return false if items.empty?
8
+ protected
11
9
 
12
- items.any? do |item|
13
- !!JsonLogic.apply(rule_applied_to_each_item, item)
14
- end
10
+ def call_with_values(values)
11
+ !values.empty? && values.any? { |value| !!value }
15
12
  end
16
13
  end
@@ -1,9 +1,32 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class JsonLogic::Operations::StrictEqual < JsonLogic::Operation
3
+ using JsonLogic::Semantics
4
+
5
+ class JsonLogic::Operations::StrictEqual < JsonLogic::LazyOperation
4
6
  def self.name = "==="
5
7
 
6
- def call((a,b), _data)
7
- a === b
8
+ def call(args, data)
9
+ raise JsonLogic::InvalidArgumentsError.new unless args.is_a?(Array) && args.size >= 2
10
+
11
+ prev = JsonLogic.apply(args.first, data)
12
+ args[1..].each do |arg|
13
+ current = JsonLogic.apply(arg, data)
14
+ return false unless strict_equal_value?(prev, current)
15
+
16
+ prev = current
17
+ end
18
+ true
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
8
31
  end
9
32
  end