shiny_json_logic 0.2.16 → 0.3.1

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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -0
  3. data/Gemfile.lock +1 -1
  4. data/README.md +1 -5
  5. data/lib/shiny_json_logic/comparisons/comparable.rb +27 -4
  6. data/lib/shiny_json_logic/engine.rb +11 -5
  7. data/lib/shiny_json_logic/numericals/min_max_collection.rb +9 -14
  8. data/lib/shiny_json_logic/numericals/numerify.rb +5 -5
  9. data/lib/shiny_json_logic/numericals/with_error_handling.rb +2 -0
  10. data/lib/shiny_json_logic/operations/addition.rb +5 -23
  11. data/lib/shiny_json_logic/operations/all.rb +1 -3
  12. data/lib/shiny_json_logic/operations/and.rb +3 -4
  13. data/lib/shiny_json_logic/operations/base.rb +13 -31
  14. data/lib/shiny_json_logic/operations/coalesce.rb +2 -2
  15. data/lib/shiny_json_logic/operations/concatenation.rb +4 -4
  16. data/lib/shiny_json_logic/operations/different.rb +2 -17
  17. data/lib/shiny_json_logic/operations/division.rb +6 -14
  18. data/lib/shiny_json_logic/operations/double_not.rb +3 -3
  19. data/lib/shiny_json_logic/operations/equal.rb +2 -16
  20. data/lib/shiny_json_logic/operations/exists.rb +4 -4
  21. data/lib/shiny_json_logic/operations/filter.rb +2 -4
  22. data/lib/shiny_json_logic/operations/greater.rb +2 -17
  23. data/lib/shiny_json_logic/operations/greater_equal.rb +2 -17
  24. data/lib/shiny_json_logic/operations/if.rb +5 -16
  25. data/lib/shiny_json_logic/operations/inclusion.rb +3 -3
  26. data/lib/shiny_json_logic/operations/iterable/base.rb +31 -61
  27. data/lib/shiny_json_logic/operations/max.rb +2 -4
  28. data/lib/shiny_json_logic/operations/merge.rb +3 -3
  29. data/lib/shiny_json_logic/operations/min.rb +2 -4
  30. data/lib/shiny_json_logic/operations/missing.rb +10 -10
  31. data/lib/shiny_json_logic/operations/missing_some.rb +7 -6
  32. data/lib/shiny_json_logic/operations/modulo.rb +6 -14
  33. data/lib/shiny_json_logic/operations/none.rb +1 -3
  34. data/lib/shiny_json_logic/operations/not.rb +2 -2
  35. data/lib/shiny_json_logic/operations/or.rb +3 -4
  36. data/lib/shiny_json_logic/operations/preserve.rb +8 -25
  37. data/lib/shiny_json_logic/operations/product.rb +7 -20
  38. data/lib/shiny_json_logic/operations/reduce.rb +24 -30
  39. data/lib/shiny_json_logic/operations/smaller.rb +2 -17
  40. data/lib/shiny_json_logic/operations/smaller_equal.rb +2 -17
  41. data/lib/shiny_json_logic/operations/some.rb +1 -3
  42. data/lib/shiny_json_logic/operations/strict_different.rb +6 -12
  43. data/lib/shiny_json_logic/operations/strict_equal.rb +6 -12
  44. data/lib/shiny_json_logic/operations/substring.rb +4 -4
  45. data/lib/shiny_json_logic/operations/subtraction.rb +7 -20
  46. data/lib/shiny_json_logic/operations/throw.rb +5 -7
  47. data/lib/shiny_json_logic/operations/try.rb +2 -3
  48. data/lib/shiny_json_logic/operations/val.rb +17 -24
  49. data/lib/shiny_json_logic/operations/var.rb +18 -16
  50. data/lib/shiny_json_logic/truthy.rb +9 -7
  51. data/lib/shiny_json_logic/utils/data_hash.rb +18 -0
  52. data/lib/shiny_json_logic/version.rb +1 -1
  53. data/lib/shiny_json_logic.rb +0 -2
  54. metadata +3 -2
@@ -7,18 +7,20 @@ require "shiny_json_logic/numericals/numerify"
7
7
  module ShinyJsonLogic
8
8
  module Operations
9
9
  class Subtraction < Base
10
- include Numericals::WithErrorHandling
11
- include Numericals::Numerify
10
+ extend Numericals::WithErrorHandling
12
11
 
13
- def call
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
  safe_arithmetic do
18
17
  result = nil
19
18
  count = 0
20
19
 
21
- each_operand(operands) do |num|
20
+ operands.each do |rule|
21
+ evaluated = evaluate(rule, scope_stack)
22
+ num = Numericals::Numerify.numerify(evaluated)
23
+ num = 0 if num.nil?
22
24
  count += 1
23
25
  result = result.nil? ? num : result - num
24
26
  end
@@ -29,21 +31,6 @@ module ShinyJsonLogic
29
31
  result
30
32
  end
31
33
  end
32
-
33
- private
34
-
35
- def each_operand(operands)
36
- operands.each do |rule|
37
- evaluated = evaluate(rule)
38
- yield numerify(evaluated)
39
- end
40
- end
41
-
42
- def numerify(value)
43
- val = super
44
- return 0 if val.nil?
45
- val
46
- end
47
34
  end
48
35
  end
49
36
  end
@@ -5,22 +5,20 @@ require "shiny_json_logic/operations/base"
5
5
  module ShinyJsonLogic
6
6
  module Operations
7
7
  class Throw < Base
8
- def call
8
+ def self.execute(rules, scope_stack)
9
9
  raw_value = rules.is_a?(Array) ? rules[0] : rules
10
10
 
11
11
  error_type =
12
- if operation?(raw_value)
13
- evaluate(raw_value)
12
+ if op?(raw_value)
13
+ evaluate(raw_value, scope_stack)
14
14
  else
15
15
  raw_value
16
16
  end
17
17
 
18
18
  extracted_type = error_type.is_a?(Hash) && error_type.key?("type") ? error_type["type"] : error_type
19
- extracted_type = self.data["type"] if extracted_type.nil?
19
+ extracted_type = scope_stack.current["type"] if extracted_type.nil?
20
20
 
21
- error = Errors::Base.new(type: extracted_type)
22
-
23
- raise error
21
+ raise Errors::Base.new(type: extracted_type)
24
22
  end
25
23
  end
26
24
  end
@@ -3,8 +3,8 @@
3
3
  module ShinyJsonLogic
4
4
  module Operations
5
5
  class Try < Base
6
- def call
7
- items = wrap_nil(rules)
6
+ def self.call(rules, scope_stack)
7
+ items = Utils::Array.wrap_nil(rules)
8
8
  last_error = nil
9
9
 
10
10
  items.each do |item|
@@ -33,7 +33,6 @@ module ShinyJsonLogic
33
33
  end
34
34
 
35
35
  last_error = e
36
- # Don't add to errors array - we're handling it
37
36
  end
38
37
  end
39
38
 
@@ -1,56 +1,48 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "shiny_json_logic/operations/base"
4
+ require "shiny_json_logic/utils/data_hash"
4
5
 
5
6
  module ShinyJsonLogic
6
7
  module Operations
7
8
  class Val < Base
8
- def call
9
- raw_keys = wrap_nil(rules)
10
-
9
+ def self.execute(rules, scope_stack)
10
+ raw_keys = Utils::Array.wrap_nil(rules)
11
+
11
12
  # {"val": []} or {"val": null} - return current scope
12
13
  if raw_keys.empty? || raw_keys == [nil]
13
- return scope_stack ? scope_stack.current : data
14
+ return Utils::DataHash.wrap(scope_stack.current)
14
15
  end
15
16
 
16
17
  # Check if first element is an array (scope navigation syntax)
17
- # {"val": [[N], "key"]} - scope navigation
18
18
  first_key = raw_keys.first
19
-
19
+
20
20
  if first_key.is_a?(Array) && scope_stack
21
21
  level_indicator = first_key.first.to_i
22
22
  remaining_keys = raw_keys[1..]
23
-
24
- # Evaluate any remaining keys that might be operations
25
- evaluated_keys = remaining_keys.map { |rule| evaluate(rule) }
26
-
27
- # Both positive and negative numbers mean "go up N levels"
28
- # [[2], "key"] = go up 2 levels
29
- # [[-2], "key"] = go up 2 levels (same as above)
23
+
24
+ evaluated_keys = remaining_keys.map { |rule| evaluate(rule, scope_stack) }
25
+
30
26
  levels = level_indicator.abs
31
- return scope_stack.resolve(levels, *evaluated_keys)
27
+ return Utils::DataHash.wrap(scope_stack.resolve(levels, *evaluated_keys))
32
28
  end
33
29
 
34
30
  # Normal case: {"val": "key"} or {"val": ["key1", "key2"]}
35
- keys = raw_keys.map { |rule| evaluate(rule) }
36
- current_data = scope_stack ? scope_stack.current : data
37
- dig_value(current_data, keys)
31
+ keys = raw_keys.map { |rule| evaluate(rule, scope_stack) }
32
+ current_data = scope_stack.current
33
+ Utils::DataHash.wrap(dig_value(current_data, keys))
38
34
  end
39
35
 
40
- private
41
-
42
- def dig_value(data, keys)
36
+ def self.dig_value(data, keys)
43
37
  return nil if data.nil?
44
38
  return data if keys.empty?
45
-
39
+
46
40
  keys.reduce(data) do |obj, key|
47
41
  return nil if obj.nil?
48
-
42
+
49
43
  if obj.is_a?(Hash)
50
- # Normalize key to string for lookup (data is already string-keyed)
51
44
  obj[key.to_s]
52
45
  elsif obj.is_a?(Array)
53
- # Convert string keys to integers for arrays
54
46
  index = key.is_a?(String) ? key.to_i : key
55
47
  obj[index]
56
48
  else
@@ -58,6 +50,7 @@ module ShinyJsonLogic
58
50
  end
59
51
  end
60
52
  end
53
+ private_class_method :dig_value
61
54
  end
62
55
  end
63
56
  end
@@ -2,36 +2,37 @@
2
2
 
3
3
  require "shiny_json_logic/truthy"
4
4
  require "shiny_json_logic/operations/base"
5
+ require "shiny_json_logic/utils/data_hash"
5
6
 
6
7
  module ShinyJsonLogic
7
8
  module Operations
8
9
  class Var < Base
9
- def call
10
- items = wrap_nil(rules)
11
- key = evaluate(items[0])
12
- default = items[1] ? evaluate(items[1]) : nil
10
+ def self.execute(rules, scope_stack)
11
+ items = Utils::Array.wrap_nil(rules)
12
+ key = evaluate(items[0], scope_stack)
13
+ default = items[1] ? evaluate(items[1], scope_stack) : nil
14
+ current_data = scope_stack.current
13
15
 
14
- return data if key.nil? || key == ""
16
+ if key.nil? || key == ""
17
+ return Utils::DataHash.wrap(current_data)
18
+ end
15
19
 
16
- result = fetch_value(data, key)
17
- result.nil? ? default : result
20
+ result = fetch_value(current_data, key)
21
+ result = result.nil? ? default : result
22
+ Utils::DataHash.wrap(result)
18
23
  rescue
19
- default || data
24
+ default || scope_stack.current
20
25
  end
21
26
 
22
- private
23
-
24
- def fetch_value(obj, key)
27
+ def self.fetch_value(obj, key)
25
28
  return nil if obj.nil?
26
-
27
- # Split dot-separated keys
29
+
28
30
  keys = key.to_s.split('.')
29
-
31
+
30
32
  keys.reduce(obj) do |current, k|
31
33
  return nil if current.nil?
32
-
34
+
33
35
  if current.is_a?(Hash)
34
- # Data is already normalized to string keys
35
36
  current[k]
36
37
  elsif current.is_a?(Array)
37
38
  current[k.to_i]
@@ -40,6 +41,7 @@ module ShinyJsonLogic
40
41
  end
41
42
  end
42
43
  end
44
+ private_class_method :fetch_value
43
45
  end
44
46
  end
45
47
  end
@@ -5,13 +5,15 @@
5
5
  module ShinyJsonLogic
6
6
  module Truthy
7
7
  def self.call(subject)
8
- return subject if [true, false].include? subject
9
- return !subject.zero? if subject.is_a? Numeric
10
- return subject.any? if subject.is_a? Array
11
- return !subject.empty? if subject.is_a? String
12
- return subject.keys.any? if subject.is_a? Hash
13
-
14
- !subject.nil?
8
+ case subject
9
+ when true, false then subject
10
+ when Numeric then !subject.zero?
11
+ when String then !subject.empty?
12
+ when Array then subject.any?
13
+ when Hash then !subject.empty?
14
+ when NilClass then false
15
+ else true
16
+ end
15
17
  end
16
18
  end
17
19
  end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShinyJsonLogic
4
+ module Utils
5
+ # A Hash subclass that marks its contents as user data (result of var/val).
6
+ # The Engine uses this to skip operator validation for these values.
7
+ class DataHash < Hash
8
+ def self.wrap(obj)
9
+ return obj unless obj.is_a?(Hash)
10
+ return obj if obj.is_a?(DataHash)
11
+
12
+ result = new
13
+ obj.each { |k, v| result[k] = v }
14
+ result
15
+ end
16
+ end
17
+ end
18
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ShinyJsonLogic
4
- VERSION = "0.2.16"
4
+ VERSION = "0.3.1"
5
5
  end
@@ -11,8 +11,6 @@ require "shiny_json_logic/scope_stack"
11
11
 
12
12
  module ShinyJsonLogic
13
13
  def self.apply(rule, data = {})
14
- validate_operators!(rule)
15
-
16
14
  normalized_data = deep_stringify_keys(data || {})
17
15
  scope_stack = ScopeStack.new(normalized_data)
18
16
  Engine.call(rule, scope_stack)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shiny_json_logic
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.16
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Luis Moyano
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-02-21 00:00:00.000000000 Z
11
+ date: 2026-02-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -177,6 +177,7 @@ files:
177
177
  - lib/shiny_json_logic/scope_stack.rb
178
178
  - lib/shiny_json_logic/truthy.rb
179
179
  - lib/shiny_json_logic/utils/array.rb
180
+ - lib/shiny_json_logic/utils/data_hash.rb
180
181
  - lib/shiny_json_logic/version.rb
181
182
  - results/ruby.json
182
183
  - shiny_json_logic.gemspec