valkey-glide-rb 1.0.0.pre.rc5 → 1.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8379ce1461414a1b5b90c6ae4b9a642427ac0226cad802e62818068599500ed7
4
- data.tar.gz: 03e1b3b0e1995887844b5055039b1cfd3187155ed91189f3e4dc1415f710343e
3
+ metadata.gz: 4f24251c31a635bac9aff04c0f4ae8027c9badf52acc0547f4dc463515b3eba7
4
+ data.tar.gz: dd7e0050d647a2782a551d9266c96ff73a9a6d3c9405dc2eecb921a6359e5aff
5
5
  SHA512:
6
- metadata.gz: 4524be6c7f7987000b4096d30466a38e6ced1f652f11a3512adf9f563d02adfd806d6fa35bea42f974e9379d9b294205ea88046083f65430d0c1f313a9f32f48
7
- data.tar.gz: a569d0aef7d271d51a1211f0105656ce53a76259ea9917e9953eb500017bbe00c22f2f63bee7e4d07f2cf29e1dc7d8a673df137ccf0fd7a72ac132e3fe50a516
6
+ metadata.gz: ee2da87f8c6c1806541476ccd752750c7320561c1010373fb7a9f679d41a321642adc6f3833b8dd04a142088a47b0ed6e9a3df03b8e34bd3c7cd0d8a2789f016
7
+ data.tar.gz: 8d862e3f9d1709a09a49dc8a2523afd5b61241a2068d73a64b2aa7db5e2d6c04d0402318877e21c7f15f96d5146c4e060b5a5085bb4236f99999012757684e8e
data/.rubocop.yml CHANGED
@@ -1,7 +1,7 @@
1
1
  inherit_from: .rubocop_todo.yml
2
2
 
3
3
  AllCops:
4
- TargetRubyVersion: 2.6
4
+ TargetRubyVersion: 3.0
5
5
  NewCops: enable
6
6
  Exclude:
7
7
  - 'vendor/**/*'
data/AGENTS.md CHANGED
@@ -4,7 +4,7 @@ This file provides AI agents and developers with the minimum but sufficient cont
4
4
 
5
5
  ## Repository Overview
6
6
 
7
- This is the **Ruby client** for Valkey GLIDE, published as the `valkey-glide-rb` gem. It provides a synchronous, redis-rb-compatible API on top of the Rust GLIDE core via FFI.
7
+ This is the **Ruby client** for Valkey GLIDE, published as the `valkey-glide-rb` gem. It provides a synchronous API on top of the Rust GLIDE core via FFI.
8
8
 
9
9
  **Primary Languages:** Ruby, Rust (FFI native library, built separately from [valkey-glide](https://github.com/valkey-io/valkey-glide))
10
10
 
@@ -20,7 +20,7 @@ This is the **Ruby client** for Valkey GLIDE, published as the `valkey-glide-rb`
20
20
  - `lib/valkey/opentelemetry.rb` — Native OTel configuration
21
21
  - `test/valkey/` — Standalone integration tests
22
22
  - `test/cluster/` — Cluster integration tests
23
- - `test/lint/` — redis-rb compatibility lint suites
23
+ - `test/lint/` — Lint suites
24
24
 
25
25
  ## Architecture Quick Facts
26
26
 
@@ -28,7 +28,7 @@ This is the **Ruby client** for Valkey GLIDE, published as the `valkey-glide-rb`
28
28
 
29
29
  **Client Types:** `Valkey` — standalone or cluster (`cluster_mode: true`)
30
30
 
31
- **API Style:** Synchronous, blocking calls (redis-rb style)
31
+ **API Style:** Synchronous, blocking calls.
32
32
 
33
33
  **Communication:** Direct FFI (`Bindings.command`, `Bindings.batch`)
34
34
 
@@ -38,7 +38,7 @@ This is the **Ruby client** for Valkey GLIDE, published as the `valkey-glide-rb`
38
38
  - Alpine Linux 3.18+ (x86_64, aarch64) — musl libc
39
39
  - macOS: 13.7+ (x86_64), 14.7+ (aarch64)
40
40
 
41
- **Ruby Versions:** 2.6, 2.7, 3.0, 3.1, 3.2, 3.3, 3.4, JRuby (CI matrix)
41
+ **Ruby Versions:** 3.0, 3.1, 3.2, 3.3, 3.4, JRuby (CI matrix)
42
42
 
43
43
  **Gem name:** `valkey-glide-rb` on RubyGems
44
44
 
@@ -162,10 +162,10 @@ cargo fmt --manifest-path ./Cargo.toml --all
162
162
 
163
163
  ### Ruby-Specific Rules
164
164
 
165
- - **Ruby 2.6+ Required:** Minimum per `valkey.gemspec`
165
+ - **Ruby 3.0+ Required:** Minimum per `valkey.gemspec`
166
166
  - **FFI dependency:** `ffi ~> 1.17.0` — do not break ABI without rebuilding native lib
167
167
  - **Synchronous only:** No async client in this repo; do not add EventMachine/async patterns without design review
168
- - **redis-rb compatibility:** Prefer matching redis-rb method signatures and return types when implementing commands
168
+ - **redis-rb conventions:** Prefer matching redis-rb method signatures and return types when implementing commands for familiarity.
169
169
  - **Command args:** All FFI args are strings; convert types in Ruby before `send_command`
170
170
  - **Pipeline transactions:** `MULTI`/`EXEC`/`DISCARD` in `pipelined` use sequential fallback — do not remove without fixing FFI batch stability
171
171
  - **OpenTelemetry:** Init once per process via `Valkey::OpenTelemetry.init`; spans created in FFI layer
@@ -220,10 +220,10 @@ valkey-glide-ruby/
220
220
  ## Quick Facts for Reasoners
221
221
 
222
222
  **Package:** `valkey-glide-rb` on RubyGems
223
- **API Style:** Synchronous, redis-rb-compatible
223
+ **API Style:** Synchronous.
224
224
  **Client:** `Valkey.new` — standalone or `cluster_mode: true`
225
225
  **Key Features:** Pipelining, OpenTelemetry (native), statistics, TLS, URL parsing, cluster routing
226
- **Testing:** Minitest + rake tasks; lint suites for redis-rb parity
226
+ **Testing:** Minitest + rake tasks; lint suites.
227
227
  **Core repo:** [valkey-glide](https://github.com/valkey-io/valkey-glide) (`ffi/`, `glide-core/`)
228
228
  **This repo:** [valkey-glide-ruby](https://github.com/valkey-io/valkey-glide-ruby)
229
229
 
data/CLAUDE.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # CLAUDE.md
2
2
 
3
- Valkey GLIDE Ruby (`valkey-glide-rb`) is the official Ruby binding for Valkey and Redis OSS. It uses the shared Rust **glide-core** driver via the **glide-ffi** C library, with a redis-rb-compatible Ruby API. This repository is separate from the [valkey-glide](https://github.com/valkey-io/valkey-glide) mono-repo (Python, Java, Node, Go).
3
+ Valkey GLIDE Ruby (`valkey-glide-rb`) is the official Ruby binding for Valkey and Redis OSS. It uses the shared Rust **glide-core** driver via the **glide-ffi** C library. This repository is separate from the [valkey-glide](https://github.com/valkey-io/valkey-glide) mono-repo (Python, Java, Node, Go).
4
4
 
5
5
  ## Hard Constraints (non-negotiable)
6
6
 
data/DEVELOPER.md CHANGED
@@ -54,7 +54,7 @@ valkey-glide-ruby/
54
54
 
55
55
  ### Software Dependencies
56
56
 
57
- - **Ruby** 2.6+ (3.x recommended for development)
57
+ - **Ruby** 3.0+
58
58
  - **Bundler**
59
59
  - **git**
60
60
  - **Valkey** or Redis OSS (for integration tests)
@@ -352,8 +352,8 @@ GitHub Actions (`.github/workflows/ci.yml`):
352
352
  | Job | Matrix |
353
353
  |-----|--------|
354
354
  | `lint` | Ruby 3.3, RuboCop |
355
- | `standalone` | Ruby 2.6–3.4 + JRuby; Valkey 7.2, 8, 8.1 |
356
- | `cluster` | Ruby 2.6–3.4; grokzen/redis-cluster |
355
+ | `standalone` | Ruby 3.0–3.4 + JRuby; Valkey 7.2, 8, 8.1 |
356
+ | `cluster` | Ruby 3.0–3.4; grokzen/redis-cluster |
357
357
 
358
358
  ## Building the Gem Locally
359
359
 
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
 
2
2
  # Valkey GLIDE for Ruby
3
3
 
4
- Valkey General Language Independent Driver for the Enterprise (GLIDE) is the official open-source Valkey client library, proudly part of the [Valkey](https://valkey.io) organization. The Ruby gem (`valkey-glide-rb`) wraps [Valkey GLIDE Core](https://github.com/valkey-io/valkey-glide) with an interface similar to [redis-rb](https://github.com/redis/redis-rb), delivering GLIDE performance, reliability, and enterprise features.
4
+ Valkey General Language Independent Driver for the Enterprise (GLIDE) is the official open-source Valkey client library, proudly part of the [Valkey](https://valkey.io) organization. The Ruby gem (`valkey-glide-rb`) wraps [Valkey GLIDE Core](https://github.com/valkey-io/valkey-glide), delivering GLIDE performance, reliability, and enterprise features.
5
5
 
6
6
  ## Why Choose Valkey GLIDE?
7
7
 
@@ -10,7 +10,6 @@ Valkey General Language Independent Driver for the Enterprise (GLIDE) is the off
10
10
  - **Performance**: Optimized for high performance and low latency via the Rust-based GLIDE core.
11
11
  - **High Availability**: Cluster-aware routing, reconnection, and fault tolerance.
12
12
  - **Cross-Language Consistency**: Same core driver as Python, Java, Node.js, and Go clients.
13
- - **Drop-in Replacement**: Familiar redis-rb-style API (`Valkey.new`, command methods, `pipelined`, URL parsing).
14
13
  - **Observability**: Native OpenTelemetry tracing and client statistics.
15
14
 
16
15
  ## Documentation
@@ -36,16 +35,13 @@ Valkey General Language Independent Driver for the Enterprise (GLIDE) is the off
36
35
 
37
36
  #### Supported OS
38
37
 
39
- The following platforms have been tested:
40
- - Ubuntu 24
41
- - Alpine Linux 3
42
- - macOS 14 (Apple silicon / ARM)
38
+ The following platforms are tested in CI:
39
+ - Ubuntu 24 (x86_64 and arm64)
40
+ - Alpine Linux 3 (x86_64 and arm64, via musl targets)
41
+ - macOS 14+ (Apple silicon / arm64)
43
42
 
44
- **Notes:**
45
- * Other Linux distributions not mentioned here should work as long as they
46
- meet the glibc 2.17+ / musl 1.2.3+ requirement above.
47
- * Only Apple silicon (ARM) macOS is shipped, with a minimum of macOS 11.
48
- Intel macOS users must build locally — see [build from source](./DEVELOPER.md).
43
+ **Notes:** valkey-glide-rb gem only support ARM MacOS. For Intel Mac users
44
+ you will need to build the client locally.
49
45
 
50
46
  ### Installation and Setup
51
47
 
@@ -87,7 +83,7 @@ client.get("mykey")
87
83
  client.close
88
84
  ```
89
85
 
90
- ### Standalone with URL (redis-rb compatible)
86
+ ### Standalone with URL
91
87
 
92
88
  Accepted URL schemes: `redis://`, `rediss://` (TLS), `valkey://`, `valkeys://` (TLS).
93
89
 
@@ -328,17 +324,17 @@ See https://github.com/valkey-io/valkey-glide-ruby/issues/135
328
324
  | `lib/valkey/pipeline.rb` | Pipeline command batching |
329
325
  | `test/valkey/` | Standalone integration tests |
330
326
  | `test/cluster/` | Cluster integration tests |
331
- | `test/lint/` | Shared lint tests (redis-rb compatibility patterns) |
327
+ | `test/lint/` | Shared lint tests (redis-rb convention patterns) |
332
328
 
333
- ## redis-rb Compatibility
329
+ ## API Conventions
334
330
 
335
- This client mirrors redis-rb conventions where possible:
331
+ This client is **not** a drop-in replacement for redis-rb, but it follows familiar Ruby conventions to ease adoption:
336
332
 
337
333
  - `Valkey.new` with `url`, `host`, `port`, `db`, `ssl_params`
338
- - Command method names and argument ordering aligned with redis-rb
334
+ - Conventional command method names and argument ordering
339
335
  - `pipelined`, `multi` / `exec`, `disconnect!` (alias of `close`)
340
336
 
341
- Not every redis-rb API is implemented yet. See the [command implementation wiki](https://github.com/valkey-io/valkey-glide-ruby/wiki/The-implementation-status-of-the-Valkey-commands) for coverage.
337
+ APIs and behavior may differ from redis-rb; verify against your usage. See the [command implementation wiki](https://github.com/valkey-io/valkey-glide-ruby/wiki/The-implementation-status-of-the-Valkey-commands) for coverage.
342
338
 
343
339
  ## Building and Testing
344
340
 
@@ -19,13 +19,13 @@ class Valkey
19
19
  # Ping the server.
20
20
  #
21
21
  # @param message [String, nil] optional message to echo back
22
- # @param route [Valkey::Route, nil] cluster routing. When routed, may return a Hash of node => value.
23
- # @return [String]
22
+ # @param route [Valkey::Route, nil] cluster routing.
23
+ # @return [String] `"PONG"`, or the echoed `message` if given.
24
24
  #
25
25
  # @example
26
- # ping #=> "PONG"
27
- # ping("hello") #=> "hello"
28
- # ping(route: Valkey::Route.all_nodes) #=> Hash (multi-node)
26
+ # ping #=> "PONG"
27
+ # ping("hello") #=> "hello"
28
+ # ping(route: Valkey::Route.all_nodes) #=> "PONG"
29
29
  def ping(message = nil, route: nil)
30
30
  send_command(RequestType::PING, [message].compact, route: route)
31
31
  end
@@ -33,8 +33,9 @@ class Valkey
33
33
  # Echo the given string.
34
34
  #
35
35
  # @param value [String]
36
- # @param route [Valkey::Route, nil] cluster routing. When routed, may return a Hash of node => value.
37
- # @return [String]
36
+ # @param route [Valkey::Route, nil] cluster routing. Default is a single random node.
37
+ # A multi-node route returns a `Hash` of `"host:port" => reply`.
38
+ # @return [String, Hash{String => String}]
38
39
  def echo(value, route: nil)
39
40
  send_command(RequestType::ECHO, [value], route: route)
40
41
  end
@@ -87,8 +88,9 @@ class Valkey
87
88
 
88
89
  # Get the current client's ID.
89
90
  #
90
- # @param route [Valkey::Route, nil] cluster routing. When routed, may return a Hash of node => value.
91
- # @return [Integer]
91
+ # @param route [Valkey::Route, nil] cluster routing. Default is a single random node.
92
+ # A multi-node route returns a `Hash` of `"host:port" => Integer`.
93
+ # @return [Integer, Hash{String => Integer}]
92
94
  def client_id(route: nil)
93
95
  send_command(RequestType::CLIENT_ID, [], route: route)
94
96
  end
@@ -161,26 +163,6 @@ class Valkey
161
163
  send_command(RequestType::CLIENT_KILL_SIMPLE, [addr])
162
164
  end
163
165
 
164
- private
165
-
166
- def build_client_kill_args(addr, options)
167
- args = []
168
- args << "ADDR" << addr if addr
169
- options.each do |key, value|
170
- case key
171
- when :id then args << "ID" << value.to_s
172
- when :type then args << "TYPE" << value.to_s
173
- when :user then args << "USER" << value.to_s
174
- when :addr then args << "ADDR" << value.to_s
175
- when :laddr then args << "LADDR" << value.to_s
176
- when :skipme then args << "SKIPME" << (value ? "yes" : "no")
177
- end
178
- end
179
- args
180
- end
181
-
182
- public
183
-
184
166
  # Pause client processing.
185
167
  #
186
168
  # @param [Integer] timeout Pause duration in milliseconds
@@ -271,6 +253,22 @@ class Valkey
271
253
 
272
254
  private
273
255
 
256
+ def build_client_kill_args(addr, options)
257
+ args = []
258
+ args << "ADDR" << addr if addr
259
+ options.each do |key, value|
260
+ case key
261
+ when :id then args << "ID" << value.to_s
262
+ when :type then args << "TYPE" << value.to_s
263
+ when :user then args << "USER" << value.to_s
264
+ when :addr then args << "ADDR" << value.to_s
265
+ when :laddr then args << "LADDR" << value.to_s
266
+ when :skipme then args << "SKIPME" << (value ? "yes" : "no")
267
+ end
268
+ end
269
+ args
270
+ end
271
+
274
272
  def build_client_tracking_args(options)
275
273
  args = []
276
274
  options.each do |key, value|
@@ -169,10 +169,10 @@ class Valkey
169
169
  #
170
170
  # @example Get function stats
171
171
  # valkey.function_stats
172
- # # => {"running_script" => {...}, "engines" => {...}}
172
+ # # => {"127.0.0.1:6379" => {"running_script" => nil, "engines" => {...}}}
173
173
  #
174
174
  # @param route [Valkey::Route, nil] cluster routing. When routed, may return a Hash of node => value.
175
- # @return [Hash] function execution statistics
175
+ # @return [Hash{String => Hash}] a Hash keyed by `"host:port"`.
176
176
  #
177
177
  # @see https://valkey.io/commands/function-stats/
178
178
  def function_stats(route: nil)
@@ -232,7 +232,8 @@ class Valkey
232
232
  #
233
233
  # @params timeout [Float] a float value specifying the maximum number of seconds to block) elapses.
234
234
  # A timeout of zero can be used to block indefinitely.
235
- # @params key [String, Array<String>] one or more keys with lists
235
+ # @params keys [String] one or more list keys, passed as separate arguments
236
+ # (splat). To pass a pre-built array, splat it at the call site: `blmpop(1.0, *keys)`.
236
237
  # @params modifier [String]
237
238
  # - when `"LEFT"` - the elements popped are those from the left of the list
238
239
  # - when `"RIGHT"` - the elements popped are those from the right of the list
@@ -258,7 +259,8 @@ class Valkey
258
259
  # valkey.lmpop('list', count: 2)
259
260
  # #=> ['list', ['a', 'b']]
260
261
  #
261
- # @params key [String, Array<String>] one or more keys with lists
262
+ # @params keys [String] one or more list keys, passed as separate arguments
263
+ # (splat). To pass a pre-built array, splat it at the call site: `lmpop(*keys)`.
262
264
  # @params modifier [String]
263
265
  # - when `"LEFT"` - the elements popped are those from the left of the list
264
266
  # - when `"RIGHT"` - the elements popped are those from the right of the list
@@ -271,8 +273,6 @@ class Valkey
271
273
  args = [keys.size, *keys, modifier]
272
274
  args << "COUNT" << Integer(count) if count
273
275
 
274
- # pp args
275
-
276
276
  send_command(RequestType::LMPOP, args)
277
277
  end
278
278
 
@@ -37,8 +37,10 @@ class Valkey
37
37
  # Sends the CONFIG GET command with the given arguments.
38
38
  #
39
39
  # @param [Array<String>] args Configuration parameters to get
40
- # @param route [Valkey::Route, nil] cluster routing. When routed, may return a Hash of node => value.
41
- # @return [Hash, String]
40
+ # @param route [Valkey::Route, nil] cluster routing. Default is a single random node.
41
+ # A multi-node route returns a `Hash` of `"host:port" => { parameter => value }`.
42
+ # @return [Hash] a flat `{ parameter => value }` Hash, or a per-node Hash under a
43
+ # multi-node route.
42
44
  #
43
45
  # @example Get all configuration parameters
44
46
  # config_get('*')
@@ -97,7 +99,8 @@ class Valkey
97
99
 
98
100
  # Return the number of keys in the selected database.
99
101
  #
100
- # @param route [Valkey::Route, nil] cluster routing. When routed, may return a Hash of node => value.
102
+ # @param route [Valkey::Route, nil] cluster routing. Multi-node routes return the
103
+ # aggregated sum across nodes, not a per-node Hash.
101
104
  # @return [Integer]
102
105
  def dbsize(route: nil)
103
106
  send_command(RequestType::DB_SIZE, [], route: route)
@@ -134,8 +137,11 @@ class Valkey
134
137
  # Get information and statistics about the server.
135
138
  #
136
139
  # @param cmd [String, Symbol, nil] section name (e.g. "commandstats")
137
- # @param route [Valkey::Route, nil] cluster routing. When routed, may return a Hash of node => value.
138
- # @return [Hash]
140
+ # @param route [Valkey::Route, nil] cluster routing. On cluster the default is all primaries,
141
+ # so the reply is a per-node Hash even with no route. Standalone (or a single-node route)
142
+ # returns a flat Hash.
143
+ # @return [Hash] a flat `{ field => value }` Hash, or a per-node
144
+ # `{ "host:port" => { field => value } }` Hash under a multi-node route.
139
145
  def info(cmd = nil, route: nil)
140
146
  send_command(RequestType::INFO, [cmd].compact, route: route) do |reply|
141
147
  if reply.is_a?(Hash)
@@ -222,11 +228,14 @@ class Valkey
222
228
  # Return the server time.
223
229
  #
224
230
  # @example
225
- # r.time # => [ 1333093196, 606806 ]
226
- #
227
- # @param route [Valkey::Route, nil] cluster routing. When routed, may return a Hash of node => value.
228
- # @return [Array<Integer>] tuple of seconds since UNIX epoch and
229
- # microseconds in the current second
231
+ # r.time # => ["1333093196", "606806"]
232
+ #
233
+ # @param route [Valkey::Route, nil] cluster routing. Default is a single random node.
234
+ # A multi-node route returns a `Hash` of `"host:port" => [seconds, microseconds]`.
235
+ # @return [Array<String>, Hash{String => Array<String>}] a two-element array of
236
+ # seconds since UNIX epoch and microseconds in the current second (both as
237
+ # strings), or a per-node Hash under a multi-node route. Call `.map(&:to_i)` on
238
+ # the array elements for arithmetic.
230
239
  def time(route: nil)
231
240
  send_command(RequestType::TIME, [], route: route)
232
241
  end
@@ -83,13 +83,11 @@ class Valkey
83
83
  # - `:xx => true`: Only set the key if it already exist.
84
84
  # - `:keepttl => true`: Retain the time to live associated with the key.
85
85
  # - `:get => true`: Return the old string stored at key, or nil if key did not exist.
86
- # @return [String, Boolean] `"OK"` or true, false if `:nx => true` or `:xx => true`
86
+ # @return [String, nil] `"OK"` on write; `nil` when `:nx` or `:xx` skipped the write.
87
87
  def set(key, value, ex: nil, px: nil, exat: nil, pxat: nil, nx: nil, xx: nil, keepttl: nil, get: nil)
88
- # value.to_s (matching redis-rb): a non-String value (e.g. an Array,
89
- # in test_set_and_get_with_non_string_value) must become ONE opaque
90
- # value here, not get flattened as if it were a multi-value list -
91
- # see build_command_args's flat_map fix for why this must happen
92
- # before command_args is built, not be left to that generic layer.
88
+ # A non-String value (e.g. an Array) must become ONE opaque value here, not
89
+ # get flattened as if it were a multi-value list -- see build_command_args's
90
+ # flat_map fix for why this must happen before command_args is built.
93
91
  args = [key, value.to_s]
94
92
  args << "EX" << Integer(ex) if ex
95
93
  args << "PX" << Integer(px) if px
@@ -101,11 +99,6 @@ class Valkey
101
99
  args << "GET" if get
102
100
 
103
101
  send_command(RequestType::SET, args)
104
- # if nx || xx
105
- # send_command(RequestType::SET, &Utils::BoolifySet))
106
- # else
107
- # send_command(RequestType::SET, args)
108
- # end
109
102
  end
110
103
 
111
104
  # Set the time to live in seconds of a key.
@@ -175,31 +175,17 @@ class Valkey
175
175
  @queued_commands = []
176
176
  end
177
177
 
178
- # Commands whose reply is boolean when run standalone (via native return-type
179
- # coercion server-side), but arrives as a raw 0/1 integer inside an EXEC array,
180
- # since that coercion is keyed by the single command actually being run - which,
181
- # for a queued command, is EXEC itself, not the original command.
182
- #
183
- # This list mirrors glide-core's own Boolean-coercion table in
184
- # `value_conversion.rs::expected_type_for_cmd` (HEXISTS, HSETNX, EXPIRE, EXPIREAT,
185
- # PEXPIRE, PEXPIREAT, SISMEMBER, PERSIST, SMOVE, PFADD, RENAMENX, MOVE, COPY,
186
- # MSETNX, XGROUP DESTROY, XGROUP CREATECONSUMER) MINUS the commands whose Ruby
187
- # method already passes its own explicit conversion block (`hexists`/`hsetnx`
188
- # use `&Utils::Boolify`; `xgroup_destroy`/`xgroup_createconsumer` use a custom
189
- # bool->int block). Those are already handled correctly by the `if block`
190
- # branch below, before this list is even consulted - listing them here too
191
- # would be redundant, not wrong. Every RequestType below calls `send_command`
192
- # with NO block at all, so this static list is the only place their boolean-ness
193
- # is recorded.
194
- #
195
- # NOTE: SETNX is deliberately NOT in glide-core's coercion table (and so isn't
196
- # here as a "no block" entry either) - it's `redis-rb`-style boolean-ness only,
197
- # not something the server/`glide-core` treats as boolean, since coercion there
198
- # is keyed by command name alone and can't distinguish this dedicated RequestType
199
- # from a raw `customCommand(["SETNX", ...])` call, which other bindings' existing
200
- # contracts expect to keep returning a plain integer. `setnx`'s own Ruby method
201
- # passes `&Utils::Boolify` directly instead - see string_commands.rb - so it's
202
- # already covered by the `if block` branch, same as hexists/hsetnx.
178
+ # Commands the server coerces to boolean by name, but which arrive as raw 0/1
179
+ # inside an EXEC array (glide-core keys coercion on the executed command - EXEC -
180
+ # not the queued ones). Listed here so #reconvert_queued_replies can restore it.
181
+ #
182
+ # This is glide-core's boolean table (`value_conversion.rs::expected_type_for_cmd`)
183
+ # minus commands whose Ruby method passes its own conversion block - those are
184
+ # handled by the `if block` branch below. Only block-less RequestTypes belong here.
185
+ #
186
+ # SETNX is absent by design: glide-core doesn't treat it as boolean (name-keyed
187
+ # coercion can't distinguish it from a raw `customCommand(["SETNX", ...])`), so
188
+ # `setnx` passes `&Utils::Boolify` itself (string_commands.rb) - covered by `if block`.
203
189
  BOOLEAN_REQUEST_TYPES = [
204
190
  RequestType::EXPIRE, RequestType::EXPIRE_AT, RequestType::PEXPIRE, RequestType::PEXPIRE_AT,
205
191
  RequestType::PERSIST, RequestType::SISMEMBER, RequestType::S_MOVE, RequestType::PFADD,
@@ -208,11 +194,10 @@ class Valkey
208
194
 
209
195
  private
210
196
 
211
- # Re-applies each queued command's own reply conversion (e.g. `&Utils::Boolify`)
212
- # to EXEC's raw array, since redis-rb's Future-based design does the equivalent
213
- # (a Future remembers its conversion and re-applies it once EXEC resolves), but
214
- # queued commands here go through the plain single-command path with no such
215
- # memory - see BOOLEAN_REQUEST_TYPES above for the case with no explicit block.
197
+ # Re-applies each queued command's reply conversion to EXEC's raw array: its own
198
+ # block if it had one, else Boolify for a BOOLEAN_REQUEST_TYPES command. Mirrors
199
+ # what redis-rb's Futures do (each remembers its conversion and re-applies it once
200
+ # EXEC resolves); glide's queued commands have no such memory, so we restore it here.
216
201
  def reconvert_queued_replies(result, queued_commands)
217
202
  return result unless result.size == queued_commands.size
218
203
 
@@ -47,7 +47,8 @@ class Valkey
47
47
  include SetCommands
48
48
  include ScriptingCommands
49
49
  include FunctionCommands
50
- include PubSubCommands
50
+ # TODO: https://github.com/valkey-io/valkey-glide-ruby/issues/135
51
+ # include PubSubCommands
51
52
  include ClusterCommands
52
53
  include TransactionCommands
53
54
  include StreamCommands
data/lib/valkey/utils.rb CHANGED
@@ -255,11 +255,11 @@ class Valkey
255
255
 
256
256
  # `URI.parse` returns userinfo *percent-encoded* (RFC 3986 §3.2.1); we
257
257
  # want the raw credential value. Callers (`Valkey#initialize`) will
258
- # re-encode with `URI::RFC2396_PARSER.escape` when composing the URI
258
+ # re-encode with `URI::DEFAULT_PARSER.escape` when composing the URI
259
259
  # they hand to the FFI, so leaving the encoded form here would
260
260
  # double-encode (`p%40ss` → `p%2540ss`). See valkey-glide/issues/6659.
261
- result[:username] = URI::RFC2396_PARSER.unescape(uri.user) if uri.user && !uri.user.empty?
262
- result[:password] = URI::RFC2396_PARSER.unescape(uri.password) if uri.password && !uri.password.empty?
261
+ result[:username] = URI::DEFAULT_PARSER.unescape(uri.user) if uri.user && !uri.user.empty?
262
+ result[:password] = URI::DEFAULT_PARSER.unescape(uri.password) if uri.password && !uri.password.empty?
263
263
 
264
264
  result
265
265
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Valkey
4
- VERSION = "1.0.0-rc5"
4
+ VERSION = "1.0.0"
5
5
  end
data/lib/valkey.rb CHANGED
@@ -46,7 +46,7 @@ class Valkey
46
46
  if options[:url]
47
47
  url_options = Utils.parse_redis_url(options[:url])
48
48
  # Merge URL options, but explicit options take precedence
49
- options = url_options.merge(options.reject { |k, _v| k == :url })
49
+ options = url_options.merge(options.except(:url))
50
50
  end
51
51
 
52
52
  # Extract connection parameters
@@ -90,19 +90,19 @@ class Valkey
90
90
  #
91
91
  # We pass an explicit `unsafe` regex — anything outside RFC 3986 §2.3
92
92
  # "unreserved" (`ALPHA / DIGIT / - . _ ~`) plus the RFC 2396 "mark" chars
93
- # (`! ~ * ' ( )`) — because `URI::RFC2396_PARSER.escape`'s default set
93
+ # (`! ~ * ' ( )`) — because `URI::DEFAULT_PARSER.escape`'s default set
94
94
  # leaves `/` and `?` raw in userinfo, which the Rust `url` crate on the
95
95
  # FFI side then rejects with "Invalid connection URI". Encoding more is
96
96
  # always safe because the FFI decodes uniformly.
97
97
  userinfo_unsafe = /[^\-_.!~*'()a-zA-Z0-9]/
98
98
  if options[:username] && options[:password]
99
- uri_parts << URI::RFC2396_PARSER.escape(options[:username], userinfo_unsafe)
99
+ uri_parts << URI::DEFAULT_PARSER.escape(options[:username], userinfo_unsafe)
100
100
  uri_parts << ":"
101
- uri_parts << URI::RFC2396_PARSER.escape(options[:password], userinfo_unsafe)
101
+ uri_parts << URI::DEFAULT_PARSER.escape(options[:password], userinfo_unsafe)
102
102
  uri_parts << "@"
103
103
  elsif options[:password]
104
104
  uri_parts << ":"
105
- uri_parts << URI::RFC2396_PARSER.escape(options[:password], userinfo_unsafe)
105
+ uri_parts << URI::DEFAULT_PARSER.escape(options[:password], userinfo_unsafe)
106
106
  uri_parts << "@"
107
107
  end
108
108
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: valkey-glide-rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.pre.rc5
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Valkey GLIDE Maintainers
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-08-07 00:00:00.000000000 Z
11
+ date: 2026-08-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi
@@ -101,7 +101,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
101
101
  requirements:
102
102
  - - ">="
103
103
  - !ruby/object:Gem::Version
104
- version: 2.6.0
104
+ version: 3.0.0
105
105
  required_rubygems_version: !ruby/object:Gem::Requirement
106
106
  requirements:
107
107
  - - ">="