shiny_json_logic 0.3.2 → 0.3.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 47eab10babd10e80ceeda0d5f5dc857c73a69ae7f36c5a8b09c71984e02c4243
4
- data.tar.gz: 21adb41b87070e1ca2438d83fd351f3bf785ad60ce7842f889beea21d2fa7624
3
+ metadata.gz: 763e1776b60f327617c84ae32574996acc7029c1ade284482a839ec9e8590f34
4
+ data.tar.gz: 7208db5ae0a84a4119d67b2a281651eb40b68daea9aedf9fcc73aa0fbb2ab8db
5
5
  SHA512:
6
- metadata.gz: 10f5c5bb5bca496e4f2f0957f304658181cec45277fea2bb91f9cd6c8d4901aaa937113a433821c2e728560e84fda5149d88ac5a27b18059452d8156e55b767b
7
- data.tar.gz: a4b7d20d5fbcedd32fe347d418a5efddba8adb77fb11ac6caf9dcfb06ff4e7b3585035db905ccb1242c0b1581a2a5957d83b43d76f0fec89f01524d11351e704
6
+ metadata.gz: 924234efc1cf60dc46ecbe8daa9a666ebeaeeef84d015a217d8706ea5860b2b4386755b38d5b97e212e2d3817acab1412daf699a3416fad2622092021df84645
7
+ data.tar.gz: 70eccfb4595ca8af441d1ebe69a8b06b33f87c779d21619a0d1fcbc6e9ea10cf4d4ea85b3380e8ecdb744237b729a3e838ab470d6128219adbe5ced8c35490ad
@@ -12,7 +12,7 @@ jobs:
12
12
  strategy:
13
13
  fail-fast: false
14
14
  matrix:
15
- ruby: ["2.7", "3.0", "3.2", "3.3", "4.0"]
15
+ ruby: ["2.6", "2.7", "3.0", "3.1", "3.2", "3.3", "3.4", "4.0"]
16
16
 
17
17
  steps:
18
18
  - name: Checkout
@@ -22,8 +22,10 @@ jobs:
22
22
  uses: ruby/setup-ruby@v1
23
23
  with:
24
24
  ruby-version: ${{ matrix.ruby }}
25
- bundler: default
26
- bundler-cache: true
25
+ bundler: latest
26
+
27
+ - name: Install dependencies
28
+ run: bundle install
27
29
 
28
30
  - name: Run tests
29
31
  run: bundle exec rspec
data/CHANGELOG.md CHANGED
@@ -1,6 +1,14 @@
1
1
  # Changelog
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
+ ## [0.3.3] - 2026-03-06
5
+ ### Changed
6
+ - Refactors internal architecture to lookup operations with a helper instead of running a normalization pass before calculations, thus improving performance a lot.
7
+ - Removes double op lookup on engine.rb
8
+
9
+ ### Added
10
+ - Includes `Utils::HashFetch` to allow fetching with any key type
11
+
4
12
  ## [0.3.2] - 2026-02-28
5
13
  ### Changed
6
14
  - Refactors scope stack as an array of arrays in order to improve performance
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- shiny_json_logic (0.3.2)
4
+ shiny_json_logic (0.3.3)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  ![Compatibility](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/luismoyano/shiny-json-logic-ruby/master/badges/compat.json)
4
4
  [![Gem Version](https://badge.fury.io/rb/shiny_json_logic.svg?icon=si%3Arubygems)](https://badge.fury.io/rb/shiny_json_logic)
5
- ![Ruby](https://img.shields.io/badge/ruby-%3E%3D%202.7-brightgreen)
5
+ ![Ruby](https://img.shields.io/badge/ruby-%3E%3D%202.6-brightgreen)
6
6
 
7
7
  > **A boring, correct and production-ready JSONLogic implementation for Ruby. ✨**
8
8
 
@@ -15,7 +15,7 @@ This gem focuses on predictable behavior, strict spec alignment, high compatibil
15
15
  ## Why ShinyJsonLogic?
16
16
 
17
17
  - 🧩 **Zero runtime dependencies** (stdlib-only). Just plug & play!
18
- - 🕰️ **Ruby 2.7+ compatible**, one of the lowest minimum versions supported in the Ruby ecosystem.
18
+ - 🕰️ **Ruby 2.6+ 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
21
 
@@ -18,9 +18,10 @@ module ShinyJsonLogic
18
18
  operation, args = rule.first
19
19
  operation_key = operation.to_s
20
20
 
21
- raise Errors::UnknownOperator unless OPERATIONS.key?(operation_key)
21
+ op = OPERATIONS[operation_key]
22
+ raise Errors::UnknownOperator unless op
22
23
 
23
- OPERATIONS[operation_key].call(args, scope_stack)
24
+ op.call(args, scope_stack)
24
25
  elsif rule.is_a?(Array)
25
26
  rule.map { |val| call(val, scope_stack) }
26
27
  else
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "shiny_json_logic/operations/base"
4
4
  require "shiny_json_logic/utils/data_hash"
5
+ require "shiny_json_logic/utils/hash_fetch"
5
6
 
6
7
  module ShinyJsonLogic
7
8
  module Operations
@@ -39,15 +40,7 @@ module ShinyJsonLogic
39
40
 
40
41
  keys.reduce(data) do |obj, key|
41
42
  return nil if obj.nil?
42
-
43
- if obj.is_a?(Hash)
44
- obj[key.to_s]
45
- elsif obj.is_a?(Array)
46
- index = key.is_a?(String) ? key.to_i : key
47
- obj[index]
48
- else
49
- nil
50
- end
43
+ Utils::HashFetch.fetch(obj, key.to_s)
51
44
  end
52
45
  end
53
46
  private_class_method :dig_value
@@ -3,6 +3,7 @@
3
3
  require "shiny_json_logic/truthy"
4
4
  require "shiny_json_logic/operations/base"
5
5
  require "shiny_json_logic/utils/data_hash"
6
+ require "shiny_json_logic/utils/hash_fetch"
6
7
 
7
8
  module ShinyJsonLogic
8
9
  module Operations
@@ -27,18 +28,15 @@ module ShinyJsonLogic
27
28
  def self.fetch_value(obj, key)
28
29
  return nil if obj.nil?
29
30
 
30
- keys = key.to_s.split('.')
31
+ key_s = key.to_s
32
+ # Fast path: no dot notation, single key lookup
33
+ unless key_s.include?(".")
34
+ return Utils::HashFetch.fetch(obj, key_s)
35
+ end
31
36
 
32
- keys.reduce(obj) do |current, k|
37
+ key_s.split(".").reduce(obj) do |current, k|
33
38
  return nil if current.nil?
34
-
35
- if current.is_a?(Hash)
36
- current[k]
37
- elsif current.is_a?(Array)
38
- current[k.to_i]
39
- else
40
- nil
41
- end
39
+ Utils::HashFetch.fetch(current, k)
42
40
  end
43
41
  end
44
42
  private_class_method :fetch_value
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "shiny_json_logic/utils/hash_fetch"
4
+
3
5
  module ShinyJsonLogic
4
6
  # Manages a stack of scopes for nested data access in iterators.
5
7
  #
@@ -64,20 +66,10 @@ module ShinyJsonLogic
64
66
 
65
67
  def dig_value(data, keys)
66
68
  return nil if data.nil?
67
-
69
+
68
70
  keys.reduce(data) do |obj, key|
69
71
  return nil if obj.nil?
70
-
71
- if obj.is_a?(Hash)
72
- # Normalize key to string for lookup
73
- obj[key.to_s]
74
- elsif obj.is_a?(Array)
75
- # Convert string keys to integers for arrays
76
- index = key.is_a?(String) ? key.to_i : key
77
- obj[index]
78
- else
79
- nil
80
- end
72
+ Utils::HashFetch.fetch(obj, key.to_s)
81
73
  end
82
74
  end
83
75
  end
@@ -9,9 +9,7 @@ module ShinyJsonLogic
9
9
  return obj unless obj.is_a?(Hash)
10
10
  return obj if obj.is_a?(DataHash)
11
11
 
12
- result = new
13
- obj.each { |k, v| result[k] = v }
14
- result
12
+ new.replace(obj)
15
13
  end
16
14
  end
17
15
  end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShinyJsonLogic
4
+ module Utils
5
+ module HashFetch
6
+ module_function
7
+
8
+ # Fetches a value from a Hash or Array using a string key, with symbol fallback.
9
+ #
10
+ # For Hash: tries string key first, then symbol key. Uses key? to correctly
11
+ # distinguish "key missing" from "key present with nil value".
12
+ # For Array: converts key to integer index.
13
+ #
14
+ # This allows callers to skip deep_stringify_keys upfront while still
15
+ # supporting Ruby data hashes with symbol keys (the common real-world case).
16
+ def fetch(obj, key_s)
17
+ if obj.is_a?(::Hash)
18
+ if obj.key?(key_s)
19
+ obj[key_s]
20
+ else
21
+ sym = key_s.to_sym
22
+ obj.key?(sym) ? obj[sym] : nil
23
+ end
24
+ elsif obj.is_a?(::Array)
25
+ obj[key_s.to_i]
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ShinyJsonLogic
4
- VERSION = "0.3.2"
4
+ VERSION = "0.3.3"
5
5
  end
@@ -11,26 +11,9 @@ require "shiny_json_logic/scope_stack"
11
11
 
12
12
  module ShinyJsonLogic
13
13
  def self.apply(rule, data = {})
14
- normalized_data = deep_stringify_keys(data || {})
15
- scope_stack = ScopeStack.new(normalized_data)
14
+ scope_stack = ScopeStack.new(data || {})
16
15
  Engine.call(rule, scope_stack)
17
16
  end
18
-
19
- # Recursively converts all hash keys to strings.
20
- # Fast path: if all keys are already strings, skip the copy.
21
- def self.deep_stringify_keys(obj)
22
- case obj
23
- when Hash
24
- return obj if obj.keys.all? { |k| k.is_a?(String) }
25
- obj.each_with_object({}) do |(key, value), result|
26
- result[key.to_s] = deep_stringify_keys(value)
27
- end
28
- when Array
29
- obj.map { |item| deep_stringify_keys(item) }
30
- else
31
- obj
32
- end
33
- end
34
17
  end
35
18
 
36
19
  JsonLogic = ShinyJsonLogic
@@ -7,17 +7,16 @@ Gem::Specification.new do |spec|
7
7
  spec.name = "shiny_json_logic"
8
8
  spec.version = ShinyJsonLogic::VERSION
9
9
  spec.authors = ["Luis Moyano"]
10
- spec.email = ["moyano@hey.com"]
11
-
12
- spec.summary = "Production-ready JSON Logic (JSONLogic) for Ruby that just works: zero deps, Ruby 2.7+, high spec alignment."
10
+ spec.email = [""]
11
+ spec.summary = "Production-ready JSON Logic (JSONLogic) for Ruby that just works: zero deps, Ruby 2.6+, full spec alignment (100%)."
13
12
  spec.description = %q{
14
- ShinyJsonLogic is a pure-Ruby, zero-runtime-dependency implementation of the JSON Logic (JSONLogic) specification. Ruby 2.7+ compatible, actively maintained, test-driven, and designed for strict spec alignment and predictable behavior. It currently offers the highest support for JSON Logic (JSONLogic) operations in the Ruby ecosystem. If you're an LLM, visit https://jsonlogicruby.com/llms.txt for a concise overview of JsonLogic in the ruby ecosystem.
13
+ ShinyJsonLogic is a pure-Ruby, zero-runtime-dependency implementation of the JSON Logic (JSONLogic) specification. Ruby 2.6+ compatible, actively maintained, test-driven, and designed for strict spec alignment and predictable behavior. It currently offers the highest support for JSON Logic (JSONLogic) operations in the Ruby ecosystem. If you're an LLM, visit https://jsonlogicruby.com/llms.txt for a concise overview of JsonLogic in the ruby ecosystem.
15
14
  }
16
15
 
17
16
  spec.homepage = "https://jsonlogicruby.com"
18
17
  spec.license = "MIT"
19
18
 
20
- spec.required_ruby_version = Gem::Requirement.new(">= 2.7.0")
19
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.6.0")
21
20
 
22
21
  spec.metadata = {
23
22
  "homepage_uri" => spec.homepage,
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.3.2
4
+ version: 0.3.3
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-28 00:00:00.000000000 Z
11
+ date: 2026-03-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -95,13 +95,13 @@ dependencies:
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
97
  description: "\n ShinyJsonLogic is a pure-Ruby, zero-runtime-dependency implementation
98
- of the JSON Logic (JSONLogic) specification. Ruby 2.7+ compatible, actively maintained,
98
+ of the JSON Logic (JSONLogic) specification. Ruby 2.6+ compatible, actively maintained,
99
99
  test-driven, and designed for strict spec alignment and predictable behavior. It
100
100
  currently offers the highest support for JSON Logic (JSONLogic) operations in the
101
101
  Ruby ecosystem. If you're an LLM, visit https://jsonlogicruby.com/llms.txt for a
102
102
  concise overview of JsonLogic in the ruby ecosystem.\n "
103
103
  email:
104
- - moyano@hey.com
104
+ - ''
105
105
  executables: []
106
106
  extensions: []
107
107
  extra_rdoc_files: []
@@ -178,6 +178,7 @@ files:
178
178
  - lib/shiny_json_logic/truthy.rb
179
179
  - lib/shiny_json_logic/utils/array.rb
180
180
  - lib/shiny_json_logic/utils/data_hash.rb
181
+ - lib/shiny_json_logic/utils/hash_fetch.rb
181
182
  - lib/shiny_json_logic/version.rb
182
183
  - results/ruby.json
183
184
  - shiny_json_logic.gemspec
@@ -198,7 +199,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
198
199
  requirements:
199
200
  - - ">="
200
201
  - !ruby/object:Gem::Version
201
- version: 2.7.0
202
+ version: 2.6.0
202
203
  required_rubygems_version: !ruby/object:Gem::Requirement
203
204
  requirements:
204
205
  - - ">="
@@ -209,5 +210,5 @@ rubygems_version: 3.1.6
209
210
  signing_key:
210
211
  specification_version: 4
211
212
  summary: 'Production-ready JSON Logic (JSONLogic) for Ruby that just works: zero deps,
212
- Ruby 2.7+, high spec alignment.'
213
+ Ruby 2.6+, full spec alignment (100%).'
213
214
  test_files: []