shiny_json_logic 0.3.4 → 0.3.6

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 (42) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +10 -0
  3. data/Gemfile.lock +1 -1
  4. data/README.md +2 -2
  5. data/lib/shiny_json_logic/comparisons/comparable.rb +15 -2
  6. data/lib/shiny_json_logic/engine.rb +12 -5
  7. data/lib/shiny_json_logic/numericals/min_max_collection.rb +21 -13
  8. data/lib/shiny_json_logic/operations/addition.rb +6 -2
  9. data/lib/shiny_json_logic/operations/all.rb +5 -3
  10. data/lib/shiny_json_logic/operations/and.rb +5 -2
  11. data/lib/shiny_json_logic/operations/base.rb +11 -4
  12. data/lib/shiny_json_logic/operations/coalesce.rb +5 -2
  13. data/lib/shiny_json_logic/operations/concatenation.rb +18 -5
  14. data/lib/shiny_json_logic/operations/division.rb +5 -2
  15. data/lib/shiny_json_logic/operations/exists.rb +8 -8
  16. data/lib/shiny_json_logic/operations/filter.rb +18 -5
  17. data/lib/shiny_json_logic/operations/inclusion.rb +16 -1
  18. data/lib/shiny_json_logic/operations/iterable/base.rb +30 -37
  19. data/lib/shiny_json_logic/operations/max.rb +1 -1
  20. data/lib/shiny_json_logic/operations/merge.rb +14 -3
  21. data/lib/shiny_json_logic/operations/min.rb +1 -1
  22. data/lib/shiny_json_logic/operations/missing.rb +34 -13
  23. data/lib/shiny_json_logic/operations/missing_some.rb +21 -5
  24. data/lib/shiny_json_logic/operations/modulo.rb +5 -2
  25. data/lib/shiny_json_logic/operations/none.rb +5 -3
  26. data/lib/shiny_json_logic/operations/or.rb +5 -2
  27. data/lib/shiny_json_logic/operations/preserve.rb +6 -4
  28. data/lib/shiny_json_logic/operations/product.rb +5 -2
  29. data/lib/shiny_json_logic/operations/reduce.rb +14 -19
  30. data/lib/shiny_json_logic/operations/some.rb +5 -1
  31. data/lib/shiny_json_logic/operations/subtraction.rb +5 -2
  32. data/lib/shiny_json_logic/operations/throw.rb +1 -1
  33. data/lib/shiny_json_logic/operations/try.rb +7 -3
  34. data/lib/shiny_json_logic/operations/val.rb +29 -8
  35. data/lib/shiny_json_logic/operations/var.rb +37 -11
  36. data/lib/shiny_json_logic/operator_solver.rb +44 -40
  37. data/lib/shiny_json_logic/scope_stack.rb +23 -53
  38. data/lib/shiny_json_logic/truthy.rb +10 -2
  39. data/lib/shiny_json_logic/utils/array.rb +1 -3
  40. data/lib/shiny_json_logic/version.rb +1 -1
  41. data/lib/shiny_json_logic.rb +1 -1
  42. metadata +1 -1
@@ -16,12 +16,15 @@ module ShinyJsonLogic
16
16
  safe_arithmetic do
17
17
  result = nil
18
18
  count = 0
19
+ i = 0
20
+ n = operands.size
19
21
 
20
- operands.each do |rule|
21
- evaluated = evaluate(rule, scope_stack)
22
+ while i < n
23
+ evaluated = evaluate(operands[i], scope_stack)
22
24
  num = Numericals::Numerify.numerify(evaluated)
23
25
  count += 1
24
26
  result = result.nil? ? num : result.remainder(num)
27
+ i += 1
25
28
  end
26
29
 
27
30
  return handle_invalid_args if count < 2
@@ -8,10 +8,12 @@ module ShinyJsonLogic
8
8
  class None < Iterable::Base
9
9
  raise_on_dynamic_args!
10
10
 
11
- def self.on_after(results, _scope_stack)
12
- return true if results.empty?
11
+ def self.on_each(_item, filter, scope_stack)
12
+ throw(:early_return, false) if Truthy.call(Engine.call(filter, scope_stack))
13
+ end
13
14
 
14
- results.none? { |res| Truthy.call(res) }
15
+ def self.on_after(results, _scope_stack)
16
+ true
15
17
  end
16
18
  end
17
19
  end
@@ -15,9 +15,12 @@ module ShinyJsonLogic
15
15
  return false if rules.empty?
16
16
 
17
17
  result = nil
18
- rules.each do |rule|
19
- result = evaluate(rule, scope_stack)
18
+ i = 0
19
+ n = rules.size
20
+ while i < n
21
+ result = evaluate(rules[i], scope_stack)
20
22
  return result if Truthy.call(result)
23
+ i += 1
21
24
  end
22
25
  result
23
26
  end
@@ -9,11 +9,13 @@ module ShinyJsonLogic
9
9
  def self.call(rules, scope_stack)
10
10
  # Preserve doesn't create new scopes - evaluates each item directly
11
11
  collection = Utils::Array.wrap(rules)
12
-
13
- results = collection.each_with_object([]) do |item, acc|
14
- acc << Engine.call(item, scope_stack)
12
+ n = collection.size
13
+ results = Array.new(n)
14
+ i = 0
15
+ while i < n
16
+ results[i] = Engine.call(collection[i], scope_stack)
17
+ i += 1
15
18
  end
16
-
17
19
  results.size == 1 ? results.first : results
18
20
  end
19
21
  end
@@ -16,14 +16,17 @@ module ShinyJsonLogic
16
16
  safe_arithmetic do
17
17
  result = nil
18
18
  count = 0
19
+ i = 0
20
+ n = operands.size
19
21
 
20
- operands.each do |rule|
21
- evaluated = evaluate(rule, scope_stack)
22
+ while i < n
23
+ evaluated = evaluate(operands[i], scope_stack)
22
24
  num = Numericals::Numerify.numerify(evaluated)
23
25
  num = 0 if num.nil?
24
26
  return handle_nan if num.nil?
25
27
  count += 1
26
28
  result = result.nil? ? num.to_f : result * num.to_f
29
+ i += 1
27
30
  end
28
31
 
29
32
  return 1 if count == 0
@@ -12,31 +12,26 @@ module ShinyJsonLogic
12
12
 
13
13
  def self.call(rules, scope_stack)
14
14
  rules = resolve_rules(rules, scope_stack)
15
+ filter = setup_filter(rules)
16
+ collection = setup_collection(rules, scope_stack)
15
17
 
16
- collection, filter = setup_collection(rules, scope_stack)
18
+ accumulator = Engine.call(rules[2], scope_stack)
17
19
 
18
- # Evaluate initial accumulator (third argument)
19
- accumulator = Engine.call(rules[2], scope_stack)
20
+ reduce_scope = { "current" => nil, "accumulator" => nil }
21
+ scope_stack << reduce_scope
20
22
 
21
- index_scope = { "index" => 0 }
22
- reduce_scope = { "current" => nil, "accumulator" => nil }
23
-
24
- collection.each_with_index do |item, index|
25
- index_scope["index"] = index
26
- reduce_scope["current"] = item
27
- reduce_scope["accumulator"] = accumulator
28
- scope_stack.push(index_scope, index: index)
29
- scope_stack.push(reduce_scope, index: index)
30
23
  begin
31
- accumulator = Engine.call(filter, scope_stack)
32
- scope_stack.pop
33
- scope_stack.pop
34
- rescue => e
35
- scope_stack.pop
24
+ i = 0
25
+ n = collection.size
26
+ while i < n
27
+ reduce_scope["current"] = collection[i]
28
+ reduce_scope["accumulator"] = accumulator
29
+ accumulator = Engine.call(filter, scope_stack)
30
+ i += 1
31
+ end
32
+ ensure
36
33
  scope_stack.pop
37
- raise e
38
34
  end
39
- end
40
35
 
41
36
  safe_arithmetic { accumulator }
42
37
  end
@@ -8,8 +8,12 @@ module ShinyJsonLogic
8
8
  class Some < Iterable::Base
9
9
  raise_on_dynamic_args!
10
10
 
11
+ def self.on_each(_item, filter, scope_stack)
12
+ throw(:early_return, true) if Truthy.call(Engine.call(filter, scope_stack))
13
+ end
14
+
11
15
  def self.on_after(results, _scope_stack)
12
- results.any? { |res| res == true }
16
+ false
13
17
  end
14
18
  end
15
19
  end
@@ -16,13 +16,16 @@ module ShinyJsonLogic
16
16
  safe_arithmetic do
17
17
  result = nil
18
18
  count = 0
19
+ i = 0
20
+ n = operands.size
19
21
 
20
- operands.each do |rule|
21
- evaluated = evaluate(rule, scope_stack)
22
+ while i < n
23
+ evaluated = evaluate(operands[i], scope_stack)
22
24
  num = Numericals::Numerify.numerify(evaluated)
23
25
  num = 0 if num.nil?
24
26
  count += 1
25
27
  result = result.nil? ? num : result - num
28
+ i += 1
26
29
  end
27
30
 
28
31
  return handle_invalid_args if count == 0
@@ -16,7 +16,7 @@ module ShinyJsonLogic
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 = scope_stack.current["type"] if extracted_type.nil?
19
+ extracted_type = scope_stack.last["type"] if extracted_type.nil?
20
20
 
21
21
  raise Errors::Base.new(type: extracted_type)
22
22
  end
@@ -6,12 +6,15 @@ module ShinyJsonLogic
6
6
  def self.call(rules, scope_stack)
7
7
  items = Utils::Array.wrap_nil(rules)
8
8
  last_error = nil
9
+ i = 0
10
+ n = items.size
9
11
 
10
- items.each do |item|
12
+ while i < n
13
+ item = items[i]
11
14
  # If previous item was an error, switch context to error payload
12
15
  if last_error
13
- scope_stack.push({}) # intermediate level for [[1]] access
14
- scope_stack.push(last_error.payload)
16
+ scope_stack << {} # intermediate level for [[1]] access
17
+ scope_stack << last_error.payload
15
18
  end
16
19
 
17
20
  begin
@@ -34,6 +37,7 @@ module ShinyJsonLogic
34
37
 
35
38
  last_error = e
36
39
  end
40
+ i += 1
37
41
  end
38
42
 
39
43
  # All items were errors, re-raise the last one
@@ -8,11 +8,21 @@ module ShinyJsonLogic
8
8
  module Operations
9
9
  class Val < Base
10
10
  def self.execute(rules, scope_stack)
11
+ # Fast path: null or empty → return current scope
12
+ if rules.nil?
13
+ return Utils::DataHash.wrap(scope_stack.last)
14
+ end
15
+
16
+ # Fast path: single string key (most common case)
17
+ if rules.is_a?(String)
18
+ return Utils::DataHash.wrap(Utils::HashFetch.fetch(scope_stack.last, rules))
19
+ end
20
+
11
21
  raw_keys = Utils::Array.wrap_nil(rules)
12
22
 
13
- # {"val": []} or {"val": null} - return current scope
23
+ # {"val": []} - return current scope
14
24
  if raw_keys.empty? || raw_keys == [nil]
15
- return Utils::DataHash.wrap(scope_stack.current)
25
+ return Utils::DataHash.wrap(scope_stack.last)
16
26
  end
17
27
 
18
28
  # Check if first element is an array (scope navigation syntax)
@@ -29,12 +39,18 @@ module ShinyJsonLogic
29
39
  end
30
40
 
31
41
  levels = level_indicator.abs
32
- return Utils::DataHash.wrap(scope_stack.resolve(levels, *evaluated_keys))
42
+ return Utils::DataHash.wrap(ScopeStack.resolve(scope_stack, levels, evaluated_keys))
33
43
  end
34
44
 
35
- # Normal case: {"val": "key"} or {"val": ["key1", "key2"]}
36
- keys = raw_keys.map { |rule| evaluate(rule, scope_stack) }
37
- current_data = scope_stack.current
45
+ # Normal case: {"val": ["key1", "key2"]}
46
+ keys_n = raw_keys.size
47
+ keys = Array.new(keys_n)
48
+ ki = 0
49
+ while ki < keys_n
50
+ keys[ki] = evaluate(raw_keys[ki], scope_stack)
51
+ ki += 1
52
+ end
53
+ current_data = scope_stack.last
38
54
  Utils::DataHash.wrap(dig_value(current_data, keys))
39
55
  end
40
56
 
@@ -42,10 +58,15 @@ module ShinyJsonLogic
42
58
  return nil if data.nil?
43
59
  return data if keys.empty?
44
60
 
45
- keys.reduce(data) do |obj, key|
61
+ obj = data
62
+ i = 0
63
+ n = keys.size
64
+ while i < n
46
65
  return nil if obj.nil?
47
- Utils::HashFetch.fetch(obj, key.to_s)
66
+ obj = Utils::HashFetch.fetch(obj, keys[i].to_s)
67
+ i += 1
48
68
  end
69
+ obj
49
70
  end
50
71
  private_class_method :dig_value
51
72
  end
@@ -9,35 +9,61 @@ module ShinyJsonLogic
9
9
  module Operations
10
10
  class Var < Base
11
11
  def self.execute(rules, scope_stack)
12
+ # Fast path: simple string key, no default
13
+ if rules.is_a?(String)
14
+ current_data = scope_stack.last
15
+ if rules.empty?
16
+ return wrap(current_data)
17
+ end
18
+ return wrap(fetch_value(current_data, rules))
19
+ end
20
+
12
21
  items = Utils::Array.wrap_nil(rules)
13
22
  key = evaluate(items[0], scope_stack)
14
- default = items[1] ? evaluate(items[1], scope_stack) : nil
15
- current_data = scope_stack.current
23
+ default = items.length > 1 ? evaluate(items[1], scope_stack) : nil
24
+ current_data = scope_stack.last
16
25
 
17
26
  if key.nil? || key == ""
18
- return Utils::DataHash.wrap(current_data)
27
+ return wrap(current_data)
19
28
  end
20
29
 
21
30
  result = fetch_value(current_data, key)
22
31
  result = result.nil? ? default : result
23
- Utils::DataHash.wrap(result)
24
- rescue
25
- default || scope_stack.current
32
+ wrap(result)
33
+ rescue
34
+ default || scope_stack.last
26
35
  end
27
36
 
37
+ # Only wrap Hash values — non-Hash values can't be confused with operators.
38
+ def self.wrap(value)
39
+ value.is_a?(::Hash) ? Utils::DataHash.wrap(value) : value
40
+ end
41
+ private_class_method :wrap
42
+
28
43
  def self.fetch_value(obj, key)
29
44
  return nil if obj.nil?
30
45
 
31
- key_s = key.to_s
32
- # Fast path: no dot notation, single key lookup
33
- unless key_s.include?(".")
46
+ key_s = key.is_a?(String) ? key : key.to_s
47
+
48
+ # Fast path: no dot notation
49
+ dot_idx = key_s.index(".")
50
+ unless dot_idx
34
51
  return Utils::HashFetch.fetch(obj, key_s)
35
52
  end
36
53
 
37
- key_s.split(".").reduce(obj) do |current, k|
54
+ # Dot notation: scan without split
55
+ current = obj
56
+ start = 0
57
+ len = key_s.length
58
+ while start < len
59
+ dot_idx = key_s.index(".", start)
60
+ segment = dot_idx ? key_s[start, dot_idx - start] : key_s[start, len - start]
38
61
  return nil if current.nil?
39
- Utils::HashFetch.fetch(current, k)
62
+ current = Utils::HashFetch.fetch(current, segment)
63
+ break unless dot_idx
64
+ start = dot_idx + 1
40
65
  end
66
+ current
41
67
  end
42
68
  private_class_method :fetch_value
43
69
  end
@@ -9,52 +9,56 @@ end
9
9
  module ShinyJsonLogic
10
10
  module OperatorSolver
11
11
  SOLVERS = {
12
- "var" => Operations::Var,
13
- "missing" => Operations::Missing,
12
+ "var" => Operations::Var,
13
+ "missing" => Operations::Missing,
14
14
  "missing_some" => Operations::MissingSome,
15
- "==" => Operations::Equal,
16
- "===" => Operations::StrictEqual,
17
- "!=" => Operations::Different,
18
- "!==" => Operations::StrictDifferent,
19
- ">" => Operations::Greater,
20
- ">=" => Operations::GreaterEqual,
21
- "<" => Operations::Smaller,
22
- "<=" => Operations::SmallerEqual,
23
- "!" => Operations::Not,
24
- "or" => Operations::Or,
25
- "and" => Operations::And,
26
- "in" => Operations::Inclusion,
27
- "cat" => Operations::Concatenation,
28
- "%" => Operations::Modulo,
29
- "max" => Operations::Max,
30
- "min" => Operations::Min,
31
- "+" => Operations::Addition,
32
- "*" => Operations::Product,
33
- "-" => Operations::Subtraction,
34
- "/" => Operations::Division,
35
- "substr" => Operations::Substring,
36
- "merge" => Operations::Merge,
37
- "!!" => Operations::DoubleNot,
38
- "val" => Operations::Val,
39
- "??" => Operations::Coalesce,
40
- "exists" => Operations::Exists,
41
- "throw" => Operations::Throw,
42
- "try" => Operations::Try,
43
- "if" => Operations::If,
44
- "?:" => Operations::If,
45
- "filter" => Operations::Filter,
46
- "map" => Operations::Map,
47
- "reduce" => Operations::Reduce,
48
- "all" => Operations::All,
49
- "none" => Operations::None,
50
- "some" => Operations::Some,
51
- "preserve" => Operations::Preserve,
15
+ "==" => Operations::Equal,
16
+ "===" => Operations::StrictEqual,
17
+ "!=" => Operations::Different,
18
+ "!==" => Operations::StrictDifferent,
19
+ ">" => Operations::Greater,
20
+ ">=" => Operations::GreaterEqual,
21
+ "<" => Operations::Smaller,
22
+ "<=" => Operations::SmallerEqual,
23
+ "!" => Operations::Not,
24
+ "or" => Operations::Or,
25
+ "and" => Operations::And,
26
+ "in" => Operations::Inclusion,
27
+ "cat" => Operations::Concatenation,
28
+ "%" => Operations::Modulo,
29
+ "max" => Operations::Max,
30
+ "min" => Operations::Min,
31
+ "+" => Operations::Addition,
32
+ "*" => Operations::Product,
33
+ "-" => Operations::Subtraction,
34
+ "/" => Operations::Division,
35
+ "substr" => Operations::Substring,
36
+ "merge" => Operations::Merge,
37
+ "!!" => Operations::DoubleNot,
38
+ "val" => Operations::Val,
39
+ "??" => Operations::Coalesce,
40
+ "exists" => Operations::Exists,
41
+ "throw" => Operations::Throw,
42
+ "try" => Operations::Try,
43
+ "if" => Operations::If,
44
+ "?:" => Operations::If,
45
+ "filter" => Operations::Filter,
46
+ "map" => Operations::Map,
47
+ "reduce" => Operations::Reduce,
48
+ "all" => Operations::All,
49
+ "none" => Operations::None,
50
+ "some" => Operations::Some,
51
+ "preserve" => Operations::Preserve,
52
52
  }.freeze
53
53
 
54
54
  SOLVER_KEYS = Set.new(SOLVERS.keys).freeze
55
55
 
56
56
  def self.operation?(value)
57
- value.keys.any? { |key| SOLVER_KEYS.include?(key.is_a?(String) ? key : key.to_s) }
57
+ # Rules always have exactly 1 key use each_key with early return
58
+ # instead of keys.any? which allocates an Array of keys first
59
+ value.each_key { |key| return SOLVER_KEYS.include?(key.to_s) }
60
+ false
58
61
  end
59
62
  end
60
63
  end
64
+
@@ -3,73 +3,43 @@
3
3
  require "shiny_json_logic/utils/hash_fetch"
4
4
 
5
5
  module ShinyJsonLogic
6
- # Manages a stack of scopes for nested data access in iterators.
6
+ # Helpers for navigating the scope stack in nested iterators.
7
7
  #
8
- # The scope stack allows:
9
- # - `current` - returns the top of the stack (current item in iterator)
10
- # - `resolve(n, *keys)` - go up n levels, then access keys via dig
11
- # - `push(scope)` / `pop` - manage stack during iteration
8
+ # The scope stack is a plain Array passed as an argument — no object instantiation.
9
+ # Each entry is a scope (Hash or value). The last entry is the current scope.
12
10
  #
13
- # When inside an iterator like map:
14
- # {"val": []} -> returns current scope (the item being iterated)
15
- # {"val": [[1], "key"]} -> go up 1 level, access "key"
16
- # {"val": [[2], "key"]} -> go up 2 levels, access "key"
11
+ # Entering/exiting a scope:
12
+ # scope_stack << item (push)
13
+ # scope_stack.pop (pop)
14
+ # scope_stack.last (current)
17
15
  #
18
- # Note: Data is normalized to string keys upfront in ShinyJsonLogic.apply,
19
- # so no indifferent access is needed here.
16
+ # Cross-level navigation (val + [[n]] syntax) uses ScopeStack.resolve.
20
17
  #
21
- class ScopeStack
22
- def initialize(root_data)
23
- @data_stack = [root_data]
24
- @index_stack = [0]
25
- end
26
-
27
- # Push a new scope onto the stack (when entering an iteration)
28
- def push(data, index: 0)
29
- @data_stack << data
30
- @index_stack << index
31
- end
32
-
33
- # Pop the top scope (when exiting an iteration)
34
- def pop
35
- if @data_stack.size > 1
36
- @data_stack.pop
37
- @index_stack.pop
38
- end
39
- end
18
+ module ScopeStack
19
+ module_function
40
20
 
41
- # Returns the current scope's data (top of stack)
42
- def current
43
- @data_stack.last
44
- end
45
-
46
- # Resolve a value by going up n levels and then accessing keys
47
- #
48
- # @param levels [Integer] number of levels to go up (0 = current, 1 = parent, etc.)
49
- # @param keys [Array] keys to dig into after reaching the target scope
50
- # @return [Object] the resolved value
51
- def resolve(levels, *keys)
52
- target_index = @data_stack.size - 1 - levels
21
+ # Resolve a value by going up n levels and then accessing keys.
22
+ # Used by val.rb for {"val": [[n], "key"]} syntax.
23
+ def resolve(stack, levels, keys)
24
+ target_index = stack.size - 1 - levels
53
25
  return nil if target_index < 0
54
26
 
55
- data = @data_stack[target_index]
56
-
57
- if keys.empty?
58
- data
59
- else
60
- dig_value(data, keys)
61
- end
27
+ data = stack[target_index]
28
+ keys.empty? ? data : dig_value(data, keys)
62
29
  end
63
30
 
64
- private
65
-
66
31
  def dig_value(data, keys)
67
32
  return nil if data.nil?
68
33
 
69
- keys.reduce(data) do |obj, key|
34
+ obj = data
35
+ i = 0
36
+ n = keys.size
37
+ while i < n
70
38
  return nil if obj.nil?
71
- Utils::HashFetch.fetch(obj, key.to_s)
39
+ obj = Utils::HashFetch.fetch(obj, keys[i].to_s)
40
+ i += 1
72
41
  end
42
+ obj
73
43
  end
74
44
  end
75
45
  end
@@ -9,9 +9,17 @@ module ShinyJsonLogic
9
9
  when true, false then subject
10
10
  when Numeric then !subject.zero?
11
11
  when String, Hash then !subject.empty?
12
- when Array then subject.any?
13
12
  when NilClass then false
14
- else true
13
+ when Array
14
+ i = 0
15
+ n = subject.size
16
+ while i < n
17
+ return true if subject[i]
18
+ i += 1
19
+ end
20
+ false
21
+ else
22
+ true
15
23
  end
16
24
  end
17
25
  end
@@ -8,16 +8,14 @@ module ShinyJsonLogic
8
8
  def wrap(object)
9
9
  return [] if object.nil?
10
10
  return object if object.is_a?(::Array)
11
- return object.to_ary || [object] if object.respond_to?(:to_ary)
12
11
 
13
12
  [object]
14
13
  end
15
14
 
16
15
  def wrap_nil(object)
17
- return [nil] if object.nil?
18
16
  return object if object.is_a?(::Array)
19
17
 
20
- wrap(object)
18
+ [object]
21
19
  end
22
20
  end
23
21
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ShinyJsonLogic
4
- VERSION = "0.3.4"
4
+ VERSION = "0.3.6"
5
5
  end
@@ -11,7 +11,7 @@ require "shiny_json_logic/scope_stack"
11
11
 
12
12
  module ShinyJsonLogic
13
13
  def self.apply(rule, data = {})
14
- scope_stack = ScopeStack.new(data || {})
14
+ scope_stack = [data || {}]
15
15
  Engine.call(rule, scope_stack)
16
16
  end
17
17
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shiny_json_logic
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.4
4
+ version: 0.3.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Luis Moyano