omq-cli 0.2.0 → 0.3.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 +4 -4
- data/CHANGELOG.md +158 -0
- data/README.md +14 -9
- data/lib/omq/cli/base_runner.rb +152 -210
- data/lib/omq/cli/cli_parser.rb +470 -0
- data/lib/omq/cli/client_server.rb +32 -59
- data/lib/omq/cli/config.rb +10 -0
- data/lib/omq/cli/expression_evaluator.rb +156 -0
- data/lib/omq/cli/formatter.rb +27 -1
- data/lib/omq/cli/pair.rb +9 -7
- data/lib/omq/cli/parallel_recv_runner.rb +150 -0
- data/lib/omq/cli/pipe.rb +175 -156
- data/lib/omq/cli/pub_sub.rb +5 -1
- data/lib/omq/cli/push_pull.rb +5 -1
- data/lib/omq/cli/radio_dish.rb +5 -1
- data/lib/omq/cli/req_rep.rb +44 -49
- data/lib/omq/cli/router_dealer.rb +13 -46
- data/lib/omq/cli/routing_helper.rb +95 -0
- data/lib/omq/cli/scatter_gather.rb +5 -1
- data/lib/omq/cli/socket_setup.rb +100 -0
- data/lib/omq/cli/transient_monitor.rb +41 -0
- data/lib/omq/cli/version.rb +1 -1
- data/lib/omq/cli.rb +72 -426
- metadata +94 -6
- data/lib/omq/cli/channel.rb +0 -8
- data/lib/omq/cli/peer.rb +0 -8
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7962982bfc0731a3f52ef7de818d9b479f60ec3046002592f92d9aed601f3047
|
|
4
|
+
data.tar.gz: 961aea9c3ecb30189672dff9bb3c29539f001a615813c9b132529034201b9681
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3e0fe43bba8360dce4daf5c8c8d46ba05010afc8a9c6958c013f3769508ea7123936b4092ff81f42d0371cf385bffc0329995ffd3f55839047135021a750cdca
|
|
7
|
+
data.tar.gz: 3fe10d13fa4c7f079d99a89423e6d7fa6ac5fab7c121ddd3518ba021ff8668bea1a65473363cf5708b8921a7712741d923713d6c982e149efe24e564315b87c6
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,163 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.0 — 2026-04-07
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- **Fix broken Gemfile** — remove deleted `omq-draft`, add all RFC gems
|
|
8
|
+
with `OMQ_DEV` path resolution.
|
|
9
|
+
- **Fix CURVE API calls** — `Curve.server` and `Curve.client` now use
|
|
10
|
+
keyword arguments to match the updated protocol-zmtp API.
|
|
11
|
+
- **Replace `require "omq/draft/all"`** with explicit RFC requires
|
|
12
|
+
(`omq/rfc/clientserver`, `radiodish`, `scattergather`, `channel`, `p2p`).
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
|
|
16
|
+
- YARD documentation on all public methods and classes.
|
|
17
|
+
- Code style: two blank lines between methods and constants.
|
|
18
|
+
|
|
19
|
+
### Refactored
|
|
20
|
+
|
|
21
|
+
- **`req_rep.rb` + `pair.rb` method extraction** — `ReqRunner#run_loop` (23 lines)
|
|
22
|
+
gains `wait_for_interval`; `RepRunner#run_loop` (27 lines) gains
|
|
23
|
+
`handle_rep_request`; `PairRunner#run_loop` (20 lines) gains `recv_async`.
|
|
24
|
+
Each `run_loop` shrinks to ~10 lines.
|
|
25
|
+
|
|
26
|
+
- **`BaseRunner` method extraction** — `call` (23 lines), `wait_for_peer` (18),
|
|
27
|
+
`read_next` (20), `run_send_logic` (29), and `compile_expr` (13) each
|
|
28
|
+
decomposed into focused helpers: `setup_socket`, `maybe_start_transient_monitor`,
|
|
29
|
+
`run_begin_blocks`, `run_end_blocks`, `wait_for_subscriber`, `apply_grace_period`,
|
|
30
|
+
`read_inline_data`, `read_stdin_input`, `run_interval_send`, `run_stdin_send`,
|
|
31
|
+
`compile_evaluator`, `assign_send_aliases`, `assign_recv_aliases`.
|
|
32
|
+
Every public-facing method is now ≤10 lines.
|
|
33
|
+
|
|
34
|
+
- **`RoutingHelper`: extract `async_send_loop`, `interval_send_loop`, `stdin_send_loop`** —
|
|
35
|
+
the sender `task.async` block was identical in `RouterRunner#run_loop` and
|
|
36
|
+
`ServerRunner#monitor_loop`. Moved to `RoutingHelper` and split into three
|
|
37
|
+
focused helpers. Both callers reduced to a 3-line orchestration.
|
|
38
|
+
`ServerRunner#reply_loop` gained `handle_server_request` to hold the 3-branch
|
|
39
|
+
dispatch, leaving the loop itself at ~8 lines.
|
|
40
|
+
|
|
41
|
+
- **`pipe.rb` method extraction** — `run_sequential` (50 lines) and `run_parallel`
|
|
42
|
+
(105 lines) decomposed into focused helpers: `build_pull_push`,
|
|
43
|
+
`apply_socket_intervals`, `setup_sequential_transient`, `sequential_message_loop`,
|
|
44
|
+
`build_socket_pairs`, `wait_for_pairs`, `setup_parallel_transient`,
|
|
45
|
+
`build_worker_data`, `spawn_workers`, `join_workers`. Each caller shrinks to
|
|
46
|
+
~8 lines.
|
|
47
|
+
|
|
48
|
+
- **Hoist `eval_proc` + `Integer#times` in Ractor worker loops** — in both
|
|
49
|
+
`ParallelRecvRunner` and `pipe.rb#spawn_workers`, `if eval_proc` was checked
|
|
50
|
+
on every message despite being invariant. Now a pre-loop branch splits into
|
|
51
|
+
two (or four, combined with `n_count`) separate loops. Count limits use
|
|
52
|
+
`n.times` instead of a manual `i` counter, eliminating the `n && n > 0`
|
|
53
|
+
check from every iteration.
|
|
54
|
+
|
|
55
|
+
- **`ExpressionEvaluator.normalize_result`** — the `case result when nil/Array/String/else`
|
|
56
|
+
block appeared in both Ractor worker bodies (`ParallelRecvRunner` and `pipe.rb`).
|
|
57
|
+
Extracted to a class method and both callers updated to use it.
|
|
58
|
+
|
|
59
|
+
- **Extract `ParallelRecvRunner`** — `BaseRunner#run_parallel_recv` (107 lines
|
|
60
|
+
of Ractor worker management) moved into `OMQ::CLI::ParallelRecvRunner` in
|
|
61
|
+
`lib/omq/cli/parallel_recv_runner.rb`. Constructor takes `klass, config, fmt,
|
|
62
|
+
output_fn`; `BaseRunner#run_parallel_recv` becomes a 4-line delegator.
|
|
63
|
+
`BaseRunner` shrinks from 426 to ~325 lines.
|
|
64
|
+
|
|
65
|
+
- **Extract `CliParser`** — `parse_options` (178 lines), `validate!` (48 lines),
|
|
66
|
+
`validate_gems!`, `DEFAULT_OPTS`, and the `EXAMPLES` heredoc (184 lines) moved
|
|
67
|
+
from the `OMQ::CLI` module into a dedicated `OMQ::CLI::CliParser` class in
|
|
68
|
+
`lib/omq/cli/cli_parser.rb`. `CLI.build_config` now calls `CliParser.parse`
|
|
69
|
+
and `CliParser.validate!`; `CLI.run_socket` calls `CliParser.validate_gems!`.
|
|
70
|
+
`cli.rb` shrinks from 674 to ~200 lines.
|
|
71
|
+
|
|
72
|
+
- **`ReqRunner#run_loop` deduplication** — the interval and non-interval
|
|
73
|
+
branches were identical loops; merged into one with a trailing
|
|
74
|
+
`sleep(wait)` gated on `config.interval`.
|
|
75
|
+
- **Remove empty runner subclasses** — `DealerRunner`, `ChannelRunner`,
|
|
76
|
+
`ClientRunner`, and `PeerRunner` were empty class bodies that added no
|
|
77
|
+
behaviour. `RUNNER_MAP` now points directly at `PairRunner`, `ReqRunner`,
|
|
78
|
+
and `ServerRunner` for those socket types. `channel.rb` and `peer.rb`
|
|
79
|
+
deleted; empty bodies removed from `router_dealer.rb` and
|
|
80
|
+
`client_server.rb`.
|
|
81
|
+
- **Extract `TransientMonitor`** — `start_disconnect_monitor`,
|
|
82
|
+
`transient_ready!`, and `@transient_barrier` removed from `BaseRunner`
|
|
83
|
+
into `OMQ::CLI::TransientMonitor`. `BaseRunner` holds a single
|
|
84
|
+
`@transient_monitor` collaborator; `transient_ready!` delegates to
|
|
85
|
+
`monitor.ready!`.
|
|
86
|
+
- **Extract `RoutingHelper` module** — `display_routing_id`, `resolve_target`,
|
|
87
|
+
and a `send_targeted_or_eval` template method (calling a `send_to_peer` hook)
|
|
88
|
+
extracted from `RouterRunner` and `ServerRunner` into a shared module.
|
|
89
|
+
`display_routing_id` and `resolve_target` removed from `BaseRunner`, which
|
|
90
|
+
never used them directly.
|
|
91
|
+
- **Extract `SocketSetup`** — socket construction (`SocketSetup.build`),
|
|
92
|
+
endpoint attachment (`SocketSetup.attach` for URL lists,
|
|
93
|
+
`SocketSetup.attach_endpoints` for `Endpoint` objects), subscription/group
|
|
94
|
+
setup (`SocketSetup.setup_subscriptions`), and CURVE configuration
|
|
95
|
+
(`SocketSetup.setup_curve`) extracted from `BaseRunner` into a stateless
|
|
96
|
+
module. `PipeRunner#attach_endpoints` now delegates to the shared module.
|
|
97
|
+
- **Extract `ExpressionEvaluator`** — expression compilation (`extract_block`,
|
|
98
|
+
`extract_blocks`, BEGIN/END parsing, proc wrapping) and result normalisation
|
|
99
|
+
live in `OMQ::CLI::ExpressionEvaluator`. Removes duplicate code from
|
|
100
|
+
`BaseRunner`, `PipeRunner`, and both Ractor worker blocks. A shared
|
|
101
|
+
`ExpressionEvaluator.compile_inside_ractor` class method replaces the
|
|
102
|
+
identical inline parse lambdas that previously appeared in each Ractor block.
|
|
103
|
+
|
|
104
|
+
### Added (OMQ::Ractor integration)
|
|
105
|
+
|
|
106
|
+
- **`-P` extended to recv-only socket types** (`pull`, `sub`, `gather`,
|
|
107
|
+
`dish`) when combined with `--recv-eval`. Each worker gets its own
|
|
108
|
+
socket connecting to the external endpoint; ZMQ distributes work
|
|
109
|
+
naturally. Results are collected via an inproc PULL back to main for
|
|
110
|
+
output. Requires all endpoints to use `--connect`.
|
|
111
|
+
- **`omq-ractor` dependency** — `OMQ::Ractor` is now used for all
|
|
112
|
+
parallel worker management.
|
|
113
|
+
|
|
114
|
+
### Changed
|
|
115
|
+
|
|
116
|
+
- **`pipe -P` rewritten using `OMQ::Ractor`** — workers no longer
|
|
117
|
+
create their own Async reactor internally. Sockets are created and
|
|
118
|
+
peer-waited in the main Async context, then passed to
|
|
119
|
+
`OMQ::Ractor.new`; worker blocks contain only pure computation.
|
|
120
|
+
Semantics are unchanged.
|
|
121
|
+
|
|
122
|
+
### Fixed
|
|
123
|
+
|
|
124
|
+
- **`-P` recv-only: stale round-robin entry** — the initial socket
|
|
125
|
+
created by `call()` was connecting to the upstream endpoint before
|
|
126
|
+
`run_parallel_recv` closed it, leaving a dead entry in the PUSH
|
|
127
|
+
peer's round-robin cycle and silently dropping 1 in every N+1
|
|
128
|
+
messages. Fixed by skipping `attach_endpoints` when `config.parallel`
|
|
129
|
+
is set.
|
|
130
|
+
- **`-P` BEGIN/END blocks in Ractor workers** — `@ivar` expressions in
|
|
131
|
+
BEGIN/END/eval blocks raised `Ractor::IsolationError` because `self`
|
|
132
|
+
inside a Ractor is a shareable object. All three procs now execute via
|
|
133
|
+
`instance_exec` on a per-worker `Object.new` context.
|
|
134
|
+
- **`-P` END block result forwarded** — the return value of an END block
|
|
135
|
+
was discarded rather than forwarded to the output socket. Now captured
|
|
136
|
+
and pushed to `push_p`, enabling patterns like
|
|
137
|
+
`BEGIN{@s=0} @s+=Integer($F.first);nil END{[@s.to_s]}` to emit once
|
|
138
|
+
per worker on exit.
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
### Added
|
|
143
|
+
|
|
144
|
+
- **`-r` defers loading to inside the Async reactor** — scripts now run
|
|
145
|
+
within the event loop and may use async APIs, OMQ sockets, etc.
|
|
146
|
+
- **Bare script mode (`omq -r FILE`)** — omitting the socket type runs the
|
|
147
|
+
script directly inside `Async{}` with free reign. The `OMQ` module is
|
|
148
|
+
included into the top-level namespace so scripts can write `PUSH.new`
|
|
149
|
+
instead of `OMQ::PUSH.new`.
|
|
150
|
+
- **`-r -` / `-r-`** — reads and evals the script from stdin, useful for
|
|
151
|
+
quick copy-paste invocations. Cannot be combined with `-F -`.
|
|
152
|
+
- **`--recv-maxsz COUNT`** — sets the ZMQ `max_message_size` socket option;
|
|
153
|
+
the socket discards incoming messages exceeding `COUNT` bytes and drops
|
|
154
|
+
the peer connection before allocation.
|
|
155
|
+
|
|
156
|
+
### Fixed
|
|
157
|
+
|
|
158
|
+
- `Protocol::ZMTP::Codec::Frame` was referenced as bare `ZMTP::Codec::Frame`
|
|
159
|
+
in the formatter (`--raw` format). Fixed the constant path.
|
|
160
|
+
|
|
3
161
|
## 0.2.0 — 2026-03-31
|
|
4
162
|
|
|
5
163
|
### Added
|
data/README.md
CHANGED
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
[](LICENSE)
|
|
5
5
|
[](https://www.ruby-lang.org)
|
|
6
6
|
|
|
7
|
-
Command-line tool for sending and receiving ZeroMQ messages on any socket type.
|
|
7
|
+
Command-line tool for sending and receiving ZeroMQ messages on any socket type.
|
|
8
|
+
Like `nngcat` from libnng, but with Ruby eval, Ractor parallelism, and message handlers.
|
|
8
9
|
|
|
9
10
|
Built on [omq](https://github.com/zeromq/omq) — pure Ruby ZeroMQ, no C dependencies.
|
|
10
11
|
|
|
@@ -46,7 +47,8 @@ omq pull -b ipc:///tmp/feed.sock # IPC (unix socket)
|
|
|
46
47
|
omq push -c ipc://@abstract # IPC (abstract namespace, Linux)
|
|
47
48
|
```
|
|
48
49
|
|
|
49
|
-
Multiple endpoints are allowed — `omq pull -b tcp://:5557 -b tcp://:5558` binds both.
|
|
50
|
+
Multiple endpoints are allowed — `omq pull -b tcp://:5557 -b tcp://:5558` binds both.
|
|
51
|
+
Pipe takes two positional endpoints (input, output) or uses `--in`/`--out` for multiple per side.
|
|
50
52
|
|
|
51
53
|
## Socket types
|
|
52
54
|
|
|
@@ -94,7 +96,8 @@ echo "hello" | omq req -c tcp://localhost:5555
|
|
|
94
96
|
| `dealer` | Like `pair` but round-robin send to multiple peers |
|
|
95
97
|
| `channel` | Like `pair` (draft, single-frame) |
|
|
96
98
|
|
|
97
|
-
These spawn two concurrent tasks: a receiver (prints incoming) and a sender (reads stdin).
|
|
99
|
+
These spawn two concurrent tasks: a receiver (prints incoming) and a sender (reads stdin).
|
|
100
|
+
`-e` transforms incoming, `-E` transforms outgoing.
|
|
98
101
|
|
|
99
102
|
### Routing sockets
|
|
100
103
|
|
|
@@ -128,7 +131,8 @@ omq pipe -c ipc://@work -c ipc://@sink -e '$F.map(&:upcase)'
|
|
|
128
131
|
omq pipe -c ipc://@work -c ipc://@sink -P 4 -r./fib.rb -e 'fib(Integer($_)).to_s'
|
|
129
132
|
```
|
|
130
133
|
|
|
131
|
-
The first endpoint is the pull-side (input), the second is the push-side (output).
|
|
134
|
+
The first endpoint is the pull-side (input), the second is the push-side (output).
|
|
135
|
+
Both must use `-c`.
|
|
132
136
|
|
|
133
137
|
## Eval: -e and -E
|
|
134
138
|
|
|
@@ -298,7 +302,8 @@ OMQ.outgoing { |msg| [*msg, Time.now.iso8601] }
|
|
|
298
302
|
| `--msgpack` | MessagePack arrays (binary stream) |
|
|
299
303
|
| `-M` / `--marshal` | Ruby Marshal (binary stream of `Array<String>` objects) |
|
|
300
304
|
|
|
301
|
-
Multipart messages: in ASCII/quoted mode, frames are tab-separated. In JSONL mode,
|
|
305
|
+
Multipart messages: in ASCII/quoted mode, frames are tab-separated. In JSONL mode,
|
|
306
|
+
each message is a JSON array.
|
|
302
307
|
|
|
303
308
|
```sh
|
|
304
309
|
# send multipart via tabs
|
|
@@ -432,7 +437,8 @@ omq pipe -c ipc://@work -c ipc://@sink --transient -e '$F.map(&:upcase)'
|
|
|
432
437
|
|
|
433
438
|
### Multi-peer pipe with `--in`/`--out`
|
|
434
439
|
|
|
435
|
-
Use `--in` and `--out` to attach multiple endpoints per side. These are modal switches — subsequent
|
|
440
|
+
Use `--in` and `--out` to attach multiple endpoints per side. These are modal switches — subsequent
|
|
441
|
+
`-b`/`-c` flags attach to the current side:
|
|
436
442
|
|
|
437
443
|
```sh
|
|
438
444
|
# fan-in: 2 producers → 1 consumer
|
|
@@ -448,9 +454,8 @@ omq pipe --in -b tcp://:5555 -b tcp://:5556 --out -c tcp://sink:5557 -e '$F'
|
|
|
448
454
|
omq pipe --in -c ipc://@a -c ipc://@b --out -c ipc://@sink -P 4 -e '$F'
|
|
449
455
|
```
|
|
450
456
|
|
|
451
|
-
`-P`/`--parallel` requires all endpoints to be `--connect`. In parallel mode, each Ractor worker
|
|
452
|
-
|
|
453
|
-
Note: in Ractor workers, use `__F` instead of `$F` (global variables aren't shared across Ractors).
|
|
457
|
+
`-P`/`--parallel` requires all endpoints to be `--connect`. In parallel mode, each Ractor worker
|
|
458
|
+
gets its own PULL/PUSH pair connecting to all endpoints.
|
|
454
459
|
|
|
455
460
|
## Transient mode
|
|
456
461
|
|