omq 0.6.1 → 0.6.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: 06ab82b849c36e97a62cfe21ddd1ecdce9901245b5d8ddb294128911e74abf03
4
- data.tar.gz: 6c7ca53bc5163e56da92036a63f1d16fcfe4de2298fdc91fc4389d93d0e21b4b
3
+ metadata.gz: 6a43ed94bf4595d9388897a74f6e642a865ec98a66c0cf64db084d6cb714705e
4
+ data.tar.gz: feb63595995ac894ea816e44f9ebf01d3bacf756cdb8c55b6f5438f00a6aab96
5
5
  SHA512:
6
- metadata.gz: '096b416cdc83f3f6773e770bdbcf4a5cc0100269867ff934623c3274826546ccc8129d862428bbcc8a042d13395b503afa329bdd6c75e99e7fb569c7b73e8a48'
7
- data.tar.gz: 62df2878bcef5f3a4d5b1c0ae2d1522853e81aaa4f03363c39fbd809e92b3c214eba1ba70c39850a7e86cace6a0c1d2290fd3d41809af22467f68a8e43d594ac
6
+ metadata.gz: 9bbe45d76566342849dcc59a8a334cf98c4f79b56392c0031e2491d4a0d3fb45d9ce7c0a9235c7138f2dd483b40721baa7fd9ce3d189c3230757f30a9c9e57f4
7
+ data.tar.gz: 1b7eccb931b57458c6cec4321fa3b4ee1de34314de7855aa3772affc434fb32561cf18e4365ab17ef5af6d5dbad62e24e7eba57d1e166d279a2b519fcfbfcf0f
data/CHANGELOG.md CHANGED
@@ -1,5 +1,32 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.6.3 — 2026-03-30
4
+
5
+ ### Fixed
6
+
7
+ - **`self << msg` in REP `-e` caused double-send** — `self << $F`
8
+ returns the socket, which `eval_expr` tried to coerce via `to_str`.
9
+ Now detected via `result.equal?(@sock)` and returned as a `SENT`
10
+ sentinel. REP skips the auto-send when the eval already sent the reply.
11
+ - **`eval_expr` called `to_str` on non-string results** — non-string,
12
+ non-array return values from `-e` now fail with a clear `NoMethodError`
13
+ on `to_str` (unchanged), but socket self-references are handled first.
14
+
15
+ ## 0.6.2 — 2026-03-30
16
+
17
+ ### Improved
18
+
19
+ - **Gemspec summary** — highlights the CLI's composable pipeline
20
+ capabilities (pipe, filter, transform, formats, Ractor parallelism).
21
+ - **README CLI section** — added `pipe`, `--transient`, `-P/--parallel`,
22
+ `BEGIN{}/END{}` blocks, `$_` variable, and `--marshal` format.
23
+
24
+ ### Fixed
25
+
26
+ - **Flaky memory leak tests on CI** — replaced global `ObjectSpace`
27
+ counting with `WeakRef` tracking of specific objects, retrying GC
28
+ until collected. No longer depends on GC generational timing.
29
+
3
30
  ## 0.6.1 — 2026-03-30
4
31
 
5
32
  ### Improved
@@ -11,6 +38,12 @@
11
38
  `pipeline_ractors.sh` now derive absolute paths from the script
12
39
  location instead of assuming the working directory is the project root.
13
40
 
41
+ ### Fixed
42
+
43
+ - **Flaky memory leak tests on CI** — replaced global `ObjectSpace`
44
+ counting with `WeakRef` tracking of specific objects, retrying GC
45
+ until collected. No longer depends on GC generational timing.
46
+
14
47
  ## 0.6.0 — 2026-03-30
15
48
 
16
49
  ### Added
data/README.md CHANGED
@@ -167,10 +167,15 @@ echo "weather.nyc 72F" | omq pub -c tcp://localhost:5556 -d 0.3
167
167
  tail -f /var/log/syslog | omq push -c tcp://collector:5557
168
168
  omq pull -b tcp://:5557 -e '$F.first.include?("error") ? $F : nil'
169
169
 
170
- # Multipart messages via tabs
171
- printf "routing-key\tpayload data" | omq push -c tcp://localhost:5557
172
- omq pull -b tcp://:5557
173
- # => routing-key payload data
170
+ # Pipe: PULL eval → PUSH in one process
171
+ omq pipe -c ipc://@work -c ipc://@sink -e '$F.map(&:upcase)'
172
+
173
+ # Pipe with 4 Ractor workers for CPU parallelism
174
+ omq pipe -c ipc://@work -c ipc://@sink -P 4 \
175
+ -r ./fib.rb -e 'fib(Integer($_)).to_s'
176
+
177
+ # Exit when all peers disconnect (pipeline workers, sinks)
178
+ omq pipe -c ipc://@work -c ipc://@sink --transient -e '$F'
174
179
 
175
180
  # JSONL for structured data
176
181
  echo '["key","value"]' | omq push -c tcp://localhost:5557 -J
@@ -186,14 +191,18 @@ omq rep -b tcp://:5555 -D "secret" --curve-server
186
191
  omq req -c tcp://localhost:5555 --curve-server-key '...'
187
192
  ```
188
193
 
189
- The `-e` flag runs Ruby inside the socket instance — the full socket API (`self <<`, `send`, `subscribe`, ...) is available. Use `-r` to require gems:
194
+ The `-e` flag runs Ruby inside the socket instance — the full socket API (`self <<`, `send`, `subscribe`, ...) is available. `$F` is the message parts array, `$_` is the first part. Use `-r` to require gems:
190
195
 
191
196
  ```sh
192
197
  omq sub -c tcp://localhost:5556 -s "" -r json \
193
198
  -e 'JSON.parse($F.first)["temperature"]'
199
+
200
+ # BEGIN/END blocks (like awk) — accumulate and summarize
201
+ omq pull -b tcp://:5557 \
202
+ -e 'BEGIN{ @sum = 0 } @sum += Integer($_); next END{ puts @sum }'
194
203
  ```
195
204
 
196
- Formats: `--ascii` (default, tab-separated), `--quoted`, `--raw`, `--jsonl`, `--msgpack`. See `omq --help` for all options.
205
+ Formats: `--ascii` (default, tab-separated), `--quoted`, `--raw`, `--jsonl`, `--msgpack`, `--marshal`. See `omq --help` for all options.
197
206
 
198
207
  ## Interop with native ZMQ
199
208
 
@@ -396,11 +396,14 @@ module OMQ
396
396
  end
397
397
 
398
398
 
399
+ SENT = Object.new.freeze # sentinel: eval already sent the reply
400
+
399
401
  def eval_expr(parts)
400
402
  return parts unless @eval_proc
401
403
  $F = parts
402
404
  result = @sock.instance_exec(&@eval_proc)
403
405
  return nil if result.nil?
406
+ return SENT if result.equal?(@sock)
404
407
  return [result] if config.format == :marshal
405
408
  case result
406
409
  when Array then result
data/lib/omq/cli/pipe.rb CHANGED
@@ -228,7 +228,7 @@ module OMQ
228
228
  return parts unless @eval_proc
229
229
  $F = parts
230
230
  result = @sock.instance_exec(&@eval_proc)
231
- return nil if result.nil?
231
+ return nil if result.nil? || result.equal?(@sock)
232
232
  return [result] if config.format == :marshal
233
233
  case result
234
234
  when Array then result
@@ -55,8 +55,10 @@ module OMQ
55
55
  break if msg.nil?
56
56
  if config.expr
57
57
  reply = eval_expr(msg)
58
- output(reply)
59
- send_msg(reply || [""])
58
+ unless reply.equal?(SENT)
59
+ output(reply)
60
+ send_msg(reply || [""])
61
+ end
60
62
  elsif config.echo
61
63
  output(msg)
62
64
  send_msg(msg)
data/lib/omq/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OMQ
4
- VERSION = "0.6.1"
4
+ VERSION = "0.6.3"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: omq
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.1
4
+ version: 0.6.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Patrik Wenger
@@ -37,8 +37,12 @@ dependencies:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
39
  version: '0.11'
40
- description: Pure Ruby implementation of the ZMTP 3.1 wire protocol (ZeroMQ) using
41
- the Async gem. No native libraries required.
40
+ description: Pure Ruby implementation of the ZMTP 3.1 wire protocol (ZeroMQ) with
41
+ all socket types (REQ/REP, PUB/SUB, PUSH/PULL, DEALER/ROUTER, and draft types) and
42
+ TCP/IPC/inproc transports. Includes an `omq` CLI for composable message pipelines
43
+ — pipe, filter, and transform across processes with Ruby eval, multiple formats
44
+ (JSON, msgpack, marshal), Ractor parallelism, and compression. No native libraries
45
+ required.
42
46
  email:
43
47
  - paddor@gmail.com
44
48
  executables:
@@ -137,5 +141,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
137
141
  requirements: []
138
142
  rubygems_version: 4.0.6
139
143
  specification_version: 4
140
- summary: OMQ pure Ruby ZeroMQ (ZMTP 3.1)
144
+ summary: Pure Ruby ZMQ library + CLI
141
145
  test_files: []