rubycli 0.1.6 → 0.2.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 +88 -0
- data/LICENSE +1 -1
- data/README.ja.md +357 -235
- data/README.md +386 -233
- data/examples/documentation_style_showcase.rb +110 -0
- data/examples/fallback_example.rb +14 -0
- data/examples/fallback_example_with_extra_docs.rb +13 -0
- data/examples/hello_app.rb +10 -0
- data/examples/hello_app_with_docs.rb +17 -0
- data/examples/hello_app_with_require.rb +19 -0
- data/examples/mismatched_constant_runner.rb +16 -0
- data/examples/multi_constant_runner.rb +20 -0
- data/examples/new_mode_runner.rb +46 -0
- data/examples/strict_choices_demo.rb +22 -0
- data/examples/typed_arguments_demo.rb +42 -0
- data/lib/rubycli/argument_mode_controller.rb +7 -11
- data/lib/rubycli/argument_parser.rb +338 -80
- data/lib/rubycli/cli.rb +26 -30
- data/lib/rubycli/command_line.rb +159 -72
- data/lib/rubycli/constant_capture.rb +563 -6
- data/lib/rubycli/documentation/metadata_parser.rb +114 -74
- data/lib/rubycli/documentation_registry.rb +1 -0
- data/lib/rubycli/environment.rb +17 -9
- data/lib/rubycli/eval_coercer.rb +27 -10
- data/lib/rubycli/help_renderer.rb +67 -62
- data/lib/rubycli/json_coercer.rb +2 -0
- data/lib/rubycli/result_emitter.rb +18 -8
- data/lib/rubycli/runner.rb +513 -0
- data/lib/rubycli/type_utils.rb +8 -6
- data/lib/rubycli/types.rb +2 -0
- data/lib/rubycli/version.rb +1 -1
- data/lib/rubycli.rb +7 -400
- metadata +59 -4
data/README.md
CHANGED
|
@@ -1,14 +1,52 @@
|
|
|
1
1
|
# Rubycli — Python Fire-inspired CLI for Ruby
|
|
2
2
|
|
|
3
|
-

|
|
3
|
+

|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[](https://rubygems.org/gems/rubycli)
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Rubycli turns existing Ruby classes and modules into command-line interfaces.
|
|
8
|
+
It inspects public method definitions and the doc comments attached to them, so
|
|
9
|
+
in the simplest case your script needs no changes at all — not even
|
|
10
|
+
`require "rubycli"`. Type annotations in comments are not just documentation:
|
|
11
|
+
they drive how CLI arguments are parsed (for example, `TAG... [String[]]`
|
|
12
|
+
forces array parsing).
|
|
8
13
|
|
|
9
|
-
|
|
14
|
+
Rubycli is inspired by [Python Fire](https://github.com/google/python-fire) but
|
|
15
|
+
is not a port or an official project; the focus is Ruby's documentation
|
|
16
|
+
conventions and type annotations.
|
|
10
17
|
|
|
11
|
-
|
|
18
|
+
> 🇯🇵 Japanese documentation: [README.ja.md](README.ja.md)
|
|
19
|
+
|
|
20
|
+

|
|
21
|
+
|
|
22
|
+
## Project status
|
|
23
|
+
|
|
24
|
+
Rubycli is **no longer maintained.** 0.2.0 is the final release and closes the
|
|
25
|
+
project out with the fixes from a full behavioural audit of the released gem
|
|
26
|
+
(eight reproducible defects; see [CHANGELOG.md](CHANGELOG.md)). Issues and pull
|
|
27
|
+
requests are not reviewed, and no further releases are planned.
|
|
28
|
+
|
|
29
|
+
The code stays online as a reference. If you are picking a CLI library for
|
|
30
|
+
production work, use [Thor](https://github.com/rails/thor),
|
|
31
|
+
[dry-cli](https://dry-rb.org/gems/dry-cli/), or Ruby's built-in
|
|
32
|
+
`OptionParser`.
|
|
33
|
+
|
|
34
|
+
## Installation
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
gem install rubycli
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
```ruby
|
|
41
|
+
# Gemfile
|
|
42
|
+
gem "rubycli"
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Requires Ruby 3.0 or later. Licensed under [MIT](LICENSE).
|
|
46
|
+
|
|
47
|
+
## Quick start
|
|
48
|
+
|
|
49
|
+
### 1. Run an existing script as-is
|
|
12
50
|
|
|
13
51
|
```ruby
|
|
14
52
|
# hello_app.rb
|
|
@@ -21,7 +59,8 @@ module HelloApp
|
|
|
21
59
|
end
|
|
22
60
|
```
|
|
23
61
|
|
|
24
|
-
|
|
62
|
+
This repository ships the same file as `examples/hello_app.rb`, so you can try
|
|
63
|
+
everything below from the project root.
|
|
25
64
|
|
|
26
65
|
```bash
|
|
27
66
|
rubycli examples/hello_app.rb
|
|
@@ -32,11 +71,13 @@ Usage: hello_app.rb COMMAND [arguments]
|
|
|
32
71
|
|
|
33
72
|
Available commands:
|
|
34
73
|
Class methods:
|
|
35
|
-
greet
|
|
74
|
+
greet NAME
|
|
36
75
|
|
|
37
76
|
Detailed command help: hello_app.rb COMMAND help
|
|
38
77
|
```
|
|
39
78
|
|
|
79
|
+
Missing arguments produce a usage message instead of a stack trace:
|
|
80
|
+
|
|
40
81
|
```bash
|
|
41
82
|
rubycli examples/hello_app.rb greet
|
|
42
83
|
```
|
|
@@ -54,16 +95,16 @@ rubycli examples/hello_app.rb greet Hanako
|
|
|
54
95
|
#=> Hello, Hanako!
|
|
55
96
|
```
|
|
56
97
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
### 2. Add documentation hints for richer flags
|
|
98
|
+
`rubycli examples/hello_app.rb --help` prints the same summary as invoking it
|
|
99
|
+
without a command.
|
|
60
100
|
|
|
61
|
-
|
|
101
|
+
### 2. Add doc comments for typed options
|
|
62
102
|
|
|
63
|
-
|
|
103
|
+
Still no `require "rubycli"` needed; comments alone drive option parsing and
|
|
104
|
+
help text. Both the concise placeholder style and YARD-style tags work:
|
|
64
105
|
|
|
65
106
|
```ruby
|
|
66
|
-
#
|
|
107
|
+
# Concise placeholder style
|
|
67
108
|
module HelloApp
|
|
68
109
|
module_function
|
|
69
110
|
|
|
@@ -77,10 +118,8 @@ module HelloApp
|
|
|
77
118
|
end
|
|
78
119
|
```
|
|
79
120
|
|
|
80
|
-
**YARD-style tags work too**
|
|
81
|
-
|
|
82
121
|
```ruby
|
|
83
|
-
#
|
|
122
|
+
# YARD-style tags
|
|
84
123
|
module HelloApp
|
|
85
124
|
module_function
|
|
86
125
|
|
|
@@ -94,21 +133,13 @@ module HelloApp
|
|
|
94
133
|
end
|
|
95
134
|
```
|
|
96
135
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
Usage: hello_app_with_docs.rb COMMAND [arguments]
|
|
105
|
-
|
|
106
|
-
Available commands:
|
|
107
|
-
Class methods:
|
|
108
|
-
greet <NAME> [--shout]
|
|
109
|
-
|
|
110
|
-
Detailed command help: hello_app_with_docs.rb COMMAND help
|
|
111
|
-
```
|
|
136
|
+
The documented variant lives at `examples/hello_app_with_docs.rb`. The module is
|
|
137
|
+
still called `HelloApp`, so the file adds `HelloAppWithDocs = HelloApp` at the
|
|
138
|
+
bottom to keep a constant that matches the file name; that is why it runs
|
|
139
|
+
without extra flags. When a file has no matching constant, see
|
|
140
|
+
[Target constant resolution](#target-constant-resolution) below.
|
|
141
|
+
(Rubycli 0.1.7 and earlier do not detect that alias, so add `--auto-target` /
|
|
142
|
+
`-a` on those versions.)
|
|
112
143
|
|
|
113
144
|
```bash
|
|
114
145
|
rubycli examples/hello_app_with_docs.rb greet --help
|
|
@@ -129,7 +160,12 @@ rubycli examples/hello_app_with_docs.rb greet --shout Hanako
|
|
|
129
160
|
#=> HELLO, HANAKO!
|
|
130
161
|
```
|
|
131
162
|
|
|
132
|
-
|
|
163
|
+
Rubycli exposes public methods defined directly on the target class or module.
|
|
164
|
+
Methods inherited from a superclass, mixed in with `include`, or generated by
|
|
165
|
+
`attr_accessor` are not turned into commands, so wrap them in the target itself
|
|
166
|
+
when you want them on the CLI.
|
|
167
|
+
|
|
168
|
+
To keep a helper off the CLI, define it as `private` on the singleton class:
|
|
133
169
|
|
|
134
170
|
```ruby
|
|
135
171
|
module HelloApp
|
|
@@ -143,78 +179,10 @@ module HelloApp
|
|
|
143
179
|
end
|
|
144
180
|
```
|
|
145
181
|
|
|
146
|
-
### 3.
|
|
147
|
-
|
|
148
|
-
Prefer to launch via `ruby ...` directly? Require the gem and delegate to `Rubycli.run` (see Quick start below for `examples/hello_app_with_require.rb`).
|
|
149
|
-
|
|
150
|
-
```bash
|
|
151
|
-
ruby examples/hello_app_with_require.rb greet Hanako --shout
|
|
152
|
-
#=> HELLO, HANAKO!
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
## Constant resolution modes
|
|
156
|
-
|
|
157
|
-
Rubycli assumes that the file name (CamelCased) matches the class or module you want to expose. When that is not the case you can choose how eagerly Rubycli should pick a constant:
|
|
158
|
-
|
|
159
|
-
| Mode | How to enable | Behaviour |
|
|
160
|
-
| --- | --- | --- |
|
|
161
|
-
| `strict` (default) | do nothing / `RUBYCLI_AUTO_TARGET=strict` | Fails unless the CamelCase name matches. The error lists the detected constants and gives explicit rerun instructions. |
|
|
162
|
-
| `auto` | `--auto-target`, `-a`, or `RUBYCLI_AUTO_TARGET=auto` | If exactly one constant in that file defines CLI-callable methods, Rubycli auto-selects it; otherwise you still get the friendly error message. |
|
|
163
|
-
|
|
164
|
-
This keeps large projects safe by default but still provides a one-flag escape hatch when you prefer the fully automatic behaviour.
|
|
165
|
-
|
|
166
|
-
> **Instance-only classes** – If a class only defines public *instance* methods (for example, it exposes functionality via `def greet` on the instance), you must run Rubycli with `--new` so the class is instantiated before commands are resolved. Otherwise Rubycli cannot see any CLI-callable methods. Add at least one public class method when you do not want to rely on `--new`. Passing `--new` also makes those instance methods appear in `rubycli --help` output and allows `rubycli --check --new` to lint their documentation.
|
|
167
|
-
|
|
168
|
-
## Project Philosophy
|
|
169
|
-
|
|
170
|
-
- **Convenience first** – The goal is to wrap existing Ruby scripts in a CLI with almost no manual plumbing. Fidelity with Python Fire is not a requirement.
|
|
171
|
-
- **Inspired, not a port** – We borrow ideas from Python Fire, but we do not aim for feature parity. Missing Fire features are generally “by design.”
|
|
172
|
-
- **Method definitions first, comments augment behavior** – Public method signatures determine what gets exposed (and which arguments are required), while doc comments like `TAG...` or `[Integer]` can turn the very same CLI value into arrays, integers, booleans, etc. Rubycli also auto-parses inputs that look like JSON/YAML literals (for example `--names='["Alice","Bob"]'`) before enforcing the documented type. Run `rubycli --check path/to/script.rb` to lint documentation mismatches—including undefined type labels or enumerated values, with DidYouMean suggestions for `Booalean`-style typos—and pass `--strict` during normal runs when you want invalid input to abort instead of merely warning.
|
|
173
|
-
- **Lightweight maintenance** – Much of the implementation was generated with AI assistance; contributions that diverge into deep Ruby metaprogramming are out of scope. Please discuss expectations before opening parity PRs.
|
|
174
|
-
|
|
175
|
-
## Features
|
|
176
|
-
|
|
177
|
-
- Comment-aware CLI generation with both YARD-style tags and concise placeholders
|
|
178
|
-
- Automatic option signature inference (`NAME [Type] Description…`) without extra DSLs
|
|
179
|
-
- Safe literal parsing out of the box (arrays / hashes / booleans) with opt-in strict JSON and Ruby eval modes
|
|
180
|
-
- Optional pre-script hook (`--pre-script` / `--init`) to evaluate Ruby and expose the resulting object
|
|
181
|
-
- Dedicated CLI flags for quality gates: `--check` lints documentation/comments without running commands, and `--strict` treats documented types/choices as hard requirements
|
|
182
|
-
|
|
183
|
-
> Tip: `--strict` trusts whatever types/choices your comments spell out—if the annotations are misspelled, runtime enforcement has nothing reliable to compare against. Keep `rubycli --check` in CI so documentation typos are caught before production runs that rely on `--strict`.
|
|
184
|
-
|
|
185
|
-
## How it differs from Python Fire
|
|
186
|
-
|
|
187
|
-
- **Comment-aware help** – Rubycli leans on doc comments when present but still reflects the live method signature, keeping code as the ultimate authority.
|
|
188
|
-
- **Type-aware parsing** – Placeholder syntax (`NAME [String]`) and YARD tags let Rubycli coerce arguments to booleans, arrays, numerics, etc. without additional code.
|
|
189
|
-
- **Strict validation** – `rubycli --check` lint runs catch documentation drift (including undefined type labels or enumerated values) without executing commands, while runtime `--strict` runs turn those documented types/choices into enforceable contracts.
|
|
190
|
-
- **Ruby-centric tooling** – Supports Ruby-specific conventions such as optional keyword arguments, block documentation (`@yield*` tags), and `RUBYCLI_*` environment toggles.
|
|
191
|
-
|
|
192
|
-
| Capability | Python Fire | Rubycli |
|
|
193
|
-
| ---------- | ----------- | -------- |
|
|
194
|
-
| Attribute traversal | Recursively exposes attributes/properties on demand | Exposes public methods defined on the target; no implicit traversal |
|
|
195
|
-
| Constructor handling | Automatically prompts for `__init__` args when instantiating classes | `--new` simply instantiates without passing CLI args (use pre-scripts or your own factories if you need injected dependencies) |
|
|
196
|
-
| Interactive shell | Offers Fire-specific REPL when invoked without command | No interactive shell mode; strictly command execution |
|
|
197
|
-
| Input discovery | Pure reflection, no doc comments required | Doc comments drive option names, placeholders, and validation |
|
|
198
|
-
| Data structures | Dictionaries / lists become subcommands by default | Focused on class or module methods; no automatic dict/list expansion |
|
|
199
|
-
|
|
200
|
-
## Installation
|
|
201
|
-
|
|
202
|
-
Rubycli is published on RubyGems.
|
|
203
|
-
|
|
204
|
-
```bash
|
|
205
|
-
gem install rubycli
|
|
206
|
-
```
|
|
182
|
+
### 3. Optional: embed the runner in your script
|
|
207
183
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
```ruby
|
|
211
|
-
# Gemfile
|
|
212
|
-
gem "rubycli"
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
## Quick start (embed Rubycli in the script)
|
|
216
|
-
|
|
217
|
-
Step 3 adds `require "rubycli"` so the script can invoke the CLI directly (see `examples/hello_app_with_require.rb`):
|
|
184
|
+
If you prefer launching via plain `ruby`, require the gem and delegate to
|
|
185
|
+
`Rubycli.run` (shipped as `examples/hello_app_with_require.rb`):
|
|
218
186
|
|
|
219
187
|
```ruby
|
|
220
188
|
# hello_app_with_require.rb
|
|
@@ -237,131 +205,219 @@ end
|
|
|
237
205
|
Rubycli.run(HelloApp)
|
|
238
206
|
```
|
|
239
207
|
|
|
240
|
-
Run it:
|
|
241
|
-
|
|
242
208
|
```bash
|
|
243
|
-
ruby examples/hello_app_with_require.rb greet Taro
|
|
244
|
-
#=> Hello, Taro!
|
|
245
|
-
|
|
246
209
|
ruby examples/hello_app_with_require.rb greet Taro --shout
|
|
247
210
|
#=> HELLO, TARO!
|
|
248
211
|
```
|
|
249
212
|
|
|
250
|
-
|
|
213
|
+
When you run a file through the bundled `rubycli` executable instead, return
|
|
214
|
+
values are printed automatically.
|
|
251
215
|
|
|
252
|
-
|
|
253
|
-
rubycli
|
|
254
|
-
|
|
216
|
+
Return values go to stdout; warnings, errors, and the usage text shown after a
|
|
217
|
+
failed invocation go to stderr, so `rubycli app.rb command > result.json` keeps
|
|
218
|
+
the payload clean and the exit status non-zero on failure.
|
|
219
|
+
|
|
220
|
+
## Target constant resolution
|
|
255
221
|
|
|
256
|
-
|
|
222
|
+
Rubycli assumes that the file name (CamelCased) matches the class or module you
|
|
223
|
+
want to expose. When it does not, choose how eagerly Rubycli should pick a
|
|
224
|
+
constant:
|
|
257
225
|
|
|
258
|
-
|
|
226
|
+
| Mode | How to enable | Behaviour |
|
|
227
|
+
| --- | --- | --- |
|
|
228
|
+
| `strict` (default) | nothing / `RUBYCLI_AUTO_TARGET=strict` | Fails unless the CamelCase name matches. The error lists the detected constants and shows how to rerun. |
|
|
229
|
+
| `auto` | `--auto-target` / `-a` / `RUBYCLI_AUTO_TARGET=auto` | If exactly one constant in the file defines CLI-callable methods, it is selected automatically. |
|
|
230
|
+
|
|
231
|
+
You can always name the constant explicitly after the file path — useful when a
|
|
232
|
+
file defines several candidates or a nested constant. Two bundled files
|
|
233
|
+
demonstrate both situations: `examples/multi_constant_runner.rb` defines
|
|
234
|
+
`MultiConstantRunner` plus `HelperRunner`, and
|
|
235
|
+
`examples/mismatched_constant_runner.rb` defines only `FriendlyGreeter`.
|
|
259
236
|
|
|
260
237
|
```bash
|
|
261
|
-
|
|
238
|
+
# pick a non-matching constant explicitly (works in the default strict mode)
|
|
239
|
+
rubycli examples/multi_constant_runner.rb HelperRunner inspect
|
|
240
|
+
#=> Helper invoked # printed by the method itself
|
|
241
|
+
#=> :helper # the return value, printed by rubycli
|
|
242
|
+
|
|
243
|
+
# or let auto mode select the single callable constant
|
|
244
|
+
rubycli -a examples/mismatched_constant_runner.rb greet Hanako --message Hi
|
|
245
|
+
#=> Hi, Hanako! # printed by the method itself
|
|
246
|
+
#=> Hi, Hanako! # the same string returned to rubycli (add --quiet to print it once)
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
Nested constants such as `Outer::Inner::Runner` are found as well; pass the
|
|
250
|
+
fully qualified name after the file path.
|
|
251
|
+
|
|
252
|
+
## Instance-only classes and `--new`
|
|
253
|
+
|
|
254
|
+
If a class only defines public *instance* methods, run Rubycli with `--new` so
|
|
255
|
+
the class is instantiated before commands are resolved; otherwise Rubycli sees
|
|
256
|
+
no CLI-callable methods.
|
|
257
|
+
|
|
258
|
+
- `--new` also makes instance methods appear in `--help` output, and lets
|
|
259
|
+
`rubycli --check --new` lint their documentation.
|
|
260
|
+
- When the constructor needs an argument, pass it with `--new=VALUE` **before
|
|
261
|
+
the file path**. The value is parsed as a safe YAML/JSON-like literal, and
|
|
262
|
+
comments on `initialize` drive type coercion just like regular CLI methods.
|
|
263
|
+
- `--new=VALUE` supplies exactly **one** value, bound to the constructor's first
|
|
264
|
+
parameter: `--new='["a","b","c"]'` hands over that array as a single argument.
|
|
265
|
+
Arrays are not spread across several parameters and hashes do not become
|
|
266
|
+
keyword arguments — reach for `--pre-script` when the constructor needs more
|
|
267
|
+
than one argument or keyword arguments.
|
|
268
|
+
- Prefer the `--new=VALUE` form over a space-separated `--new VALUE`, so the
|
|
269
|
+
value is not mistaken for the file path.
|
|
270
|
+
- A `--pre-script` that returns an instance exposes instance methods on its own,
|
|
271
|
+
so it can be used instead of `--new`, not only alongside it.
|
|
272
|
+
|
|
273
|
+
Example (`examples/new_mode_runner.rb`):
|
|
274
|
+
|
|
275
|
+
```bash
|
|
276
|
+
rubycli --new='["a","b","c"]' examples/new_mode_runner.rb run --mode reverse
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
```text
|
|
280
|
+
[
|
|
281
|
+
"c",
|
|
282
|
+
"b",
|
|
283
|
+
"a"
|
|
284
|
+
]
|
|
262
285
|
```
|
|
263
286
|
|
|
264
|
-
|
|
287
|
+
Return values are rendered as pretty-printed JSON when a command returns a
|
|
288
|
+
structure instead of printing it.
|
|
265
289
|
|
|
266
290
|
## Comment syntax
|
|
267
291
|
|
|
268
|
-
Rubycli parses a hybrid format
|
|
292
|
+
Rubycli parses a hybrid format — familiar YARD tags or short forms:
|
|
269
293
|
|
|
270
294
|
| Purpose | YARD-compatible | Rubycli style |
|
|
271
295
|
| ------- | --------------- | ------------- |
|
|
272
296
|
| Positional argument | `@param name [Type] Description` | `NAME [Type] Description` |
|
|
273
|
-
| Keyword option |
|
|
297
|
+
| Keyword option | same | `--flag -f VALUE [Type] Description` |
|
|
274
298
|
| Return value | `@return [Type] Description` | `=> [Type] Description` |
|
|
275
299
|
|
|
276
|
-
Short options are optional and order-independent
|
|
300
|
+
Short options are optional and order-independent; these are equivalent:
|
|
277
301
|
|
|
278
302
|
- `--flag -f VALUE [Type] Description`
|
|
279
303
|
- `--flag VALUE [Type] Description`
|
|
280
304
|
- `-f --flag VALUE [Type] Description`
|
|
281
305
|
|
|
282
|
-
|
|
306
|
+
Types can be written as `[String]` or `(String)`, and unions as
|
|
307
|
+
`(String, nil)`.
|
|
283
308
|
|
|
284
309
|
### Alternate placeholder notations
|
|
285
310
|
|
|
286
|
-
|
|
311
|
+
These are understood both when parsing comments and when rendering help:
|
|
287
312
|
|
|
288
|
-
- Angle brackets
|
|
289
|
-
- Inline equals
|
|
290
|
-
- Trailing ellipsis for repeated values: `VALUE
|
|
313
|
+
- Angle brackets: `--flag <value>`, `NAME [<value>]`
|
|
314
|
+
- Inline equals: `--flag=<value>`
|
|
315
|
+
- Trailing ellipsis for repeated values: `VALUE...`, `<value>...`
|
|
291
316
|
|
|
292
|
-
|
|
317
|
+
At runtime `--flag VALUE`, `--flag <value>`, and `--flag=<value>` are
|
|
318
|
+
identical — document with whichever variant your team prefers. You do not need
|
|
319
|
+
to bracket optional arguments yourself: Rubycli already knows which parameters
|
|
320
|
+
are optional from the Ruby signature and adds the brackets in generated help.
|
|
293
321
|
|
|
294
|
-
|
|
322
|
+
Inference rules when annotations are partial:
|
|
295
323
|
|
|
296
|
-
|
|
324
|
+
- A bare placeholder such as `ARG1` (no type) is treated as `String`.
|
|
325
|
+
- An option with no value placeholder (`--verbose`) becomes a Boolean flag.
|
|
326
|
+
- Positional arguments only become booleans with an explicit `[Boolean]`;
|
|
327
|
+
a bare `NAME Description` falls back to `String` regardless of the Ruby
|
|
328
|
+
default value.
|
|
297
329
|
|
|
298
|
-
|
|
330
|
+
### Arrays and repeated values
|
|
299
331
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
332
|
+
Options documented with an ellipsis (`TAG...`) or an array type
|
|
333
|
+
(`[String[]]`, `Array<String>`) are parsed as arrays. Both JSON/YAML list
|
|
334
|
+
syntax (`--tags '["build","test"]'`) and comma-delimited strings
|
|
335
|
+
(`--tags "build,test"`) are accepted. Space-separated multi-value flags
|
|
336
|
+
(`--tags build test`) are not supported, and options without a repeated/array
|
|
337
|
+
hint stay scalars. `--strict` verifies each element against the documented
|
|
338
|
+
type, so `--tags [1,2]` fails when the docs say `[String[]]`. Quoted elements
|
|
339
|
+
remain strings even when their contents look like other literals, such as
|
|
340
|
+
`--tags '["true","null"]'`.
|
|
308
341
|
|
|
309
342
|
### Literal choices and enums
|
|
310
343
|
|
|
311
|
-
|
|
344
|
+
A finite set of accepted values can be written directly inside the type
|
|
345
|
+
annotation: `--format MODE [:json, :yaml, :auto]` or `LEVEL [:info, :warn]`.
|
|
346
|
+
Symbols, strings (including barewords), booleans, numbers, and `nil` are
|
|
347
|
+
supported; literals can be mixed with broader types
|
|
348
|
+
(`--channel TARGET [:stdout, :stderr, Boolean]`), and `%i[info warn]` /
|
|
349
|
+
`%w[debug info]` shorthands expand as expected. The choices always appear in
|
|
350
|
+
generated help; without `--strict` an out-of-range value only prints a warning,
|
|
351
|
+
with `--strict` it aborts.
|
|
312
352
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
353
|
+
Symbols and strings are compared strictly: `[:info, :warn]` requires symbol
|
|
354
|
+
input such as `:info` (prefix the value with `:` at the CLI), while
|
|
355
|
+
`["info", "warn"]` only accepts plain strings.
|
|
316
356
|
|
|
317
357
|
```bash
|
|
318
|
-
#
|
|
319
|
-
|
|
320
|
-
#=> [WARN] format=json
|
|
358
|
+
# see examples/strict_choices_demo.rb — LEVEL is documented as [:info, :warn, :error]
|
|
359
|
+
rubycli examples/strict_choices_demo.rb report :warn --format json
|
|
360
|
+
#=> [WARN] format=json (followed by the returned hash)
|
|
321
361
|
|
|
322
|
-
#
|
|
323
|
-
|
|
324
|
-
#=>
|
|
325
|
-
```
|
|
362
|
+
# a plain string is not the documented symbol: warn and continue
|
|
363
|
+
rubycli examples/strict_choices_demo.rb report warn
|
|
364
|
+
#=> [WARN] LEVEL must be one of :info, :warn, :error (received "warn") (use --strict to abort on invalid input)
|
|
326
365
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
#=> [WARN] format=text
|
|
331
|
-
|
|
332
|
-
ruby -Ilib exe/rubycli --strict examples/strict_choices_demo.rb report warn
|
|
333
|
-
#=> Rubycli::ArgumentError: Value "warn" for LEVEL is not allowed: allowed values are :info, :warn, :error
|
|
366
|
+
# with --strict, out-of-range input aborts
|
|
367
|
+
rubycli --strict examples/strict_choices_demo.rb report debug
|
|
368
|
+
#=> [ERROR] LEVEL must be one of :info, :warn, :error (received "debug")
|
|
334
369
|
```
|
|
335
370
|
|
|
371
|
+
Literal enums currently apply to each scalar argument; combined literal arrays
|
|
372
|
+
such as `[%i[foo bar][]]` are not supported.
|
|
373
|
+
|
|
336
374
|
### Standard library type hints
|
|
337
375
|
|
|
338
|
-
Doc comments can reference standard classes such as `Date`, `Time`,
|
|
376
|
+
Doc comments can reference standard classes such as `Date`, `Time`,
|
|
377
|
+
`BigDecimal`, or `Pathname`. Rubycli loads the required stdlib on demand and
|
|
378
|
+
coerces CLI inputs, so the handler receives real objects without manual
|
|
379
|
+
parsing:
|
|
339
380
|
|
|
340
381
|
```bash
|
|
341
382
|
# see examples/typed_arguments_demo.rb
|
|
342
|
-
|
|
383
|
+
rubycli examples/typed_arguments_demo.rb ingest \
|
|
343
384
|
--date 2024-12-25 \
|
|
344
385
|
--moment 2024-12-25T10:00:00Z \
|
|
345
386
|
--budget 123.45 \
|
|
346
387
|
--input ./data/input.csv
|
|
347
388
|
```
|
|
348
389
|
|
|
349
|
-
|
|
390
|
+
Every option there has a default, so you can also experiment one at a time
|
|
391
|
+
(`... ingest --budget 999.99`).
|
|
350
392
|
|
|
351
|
-
|
|
393
|
+
Other YARD tags such as `@example`, `@raise`, `@see`, and `@deprecated` are
|
|
394
|
+
currently ignored by the help renderer.
|
|
352
395
|
|
|
353
|
-
|
|
396
|
+
> To explore every notation in one script, try
|
|
397
|
+
> `rubycli examples/documentation_style_showcase.rb canonical --help` and the
|
|
398
|
+
> other showcase commands.
|
|
354
399
|
|
|
355
|
-
|
|
400
|
+
### Notes on YARD-style comments
|
|
356
401
|
|
|
357
|
-
|
|
402
|
+
- Methods that accept `**kwargs` do not expose those keys automatically; every
|
|
403
|
+
key you want on the CLI needs its own `--long-name PLACEHOLDER [Type] ...`
|
|
404
|
+
line.
|
|
405
|
+
- Bullet lists or free-form lines following a `@param` line are not used for
|
|
406
|
+
CLI generation; put supplementary text in the option's description instead.
|
|
407
|
+
- To migrate towards the concise placeholder syntax, set
|
|
408
|
+
`RUBYCLI_ALLOW_PARAM_COMMENT=OFF` and run `rubycli --check`: every `@param`
|
|
409
|
+
line is then reported as a documentation issue (and ignored for that lint
|
|
410
|
+
run), so you can see what still needs rewriting. It is a linting switch, not
|
|
411
|
+
a runtime restriction — normal runs keep honouring `@param` unchanged, and
|
|
412
|
+
`@return` is never affected.
|
|
358
413
|
|
|
359
414
|
### When docs are missing or incomplete
|
|
360
415
|
|
|
361
|
-
Rubycli always trusts the live method signature.
|
|
416
|
+
Rubycli always trusts the live method signature. Undocumented parameters are
|
|
417
|
+
still exposed, with names, defaults, and types inferred from the definition:
|
|
362
418
|
|
|
363
419
|
```ruby
|
|
364
|
-
# fallback_example.rb
|
|
420
|
+
# examples/fallback_example.rb
|
|
365
421
|
module FallbackExample
|
|
366
422
|
module_function
|
|
367
423
|
|
|
@@ -375,20 +431,6 @@ module FallbackExample
|
|
|
375
431
|
end
|
|
376
432
|
```
|
|
377
433
|
|
|
378
|
-
```bash
|
|
379
|
-
rubycli examples/fallback_example.rb
|
|
380
|
-
```
|
|
381
|
-
|
|
382
|
-
```text
|
|
383
|
-
Usage: fallback_example.rb COMMAND [arguments]
|
|
384
|
-
|
|
385
|
-
Available commands:
|
|
386
|
-
Class methods:
|
|
387
|
-
scale AMOUNT [<FACTOR>] [--clamp=<value>] [--notify]
|
|
388
|
-
|
|
389
|
-
Detailed command help: fallback_example.rb COMMAND help
|
|
390
|
-
```
|
|
391
|
-
|
|
392
434
|
```bash
|
|
393
435
|
rubycli examples/fallback_example.rb scale --help
|
|
394
436
|
```
|
|
@@ -398,107 +440,218 @@ Usage: fallback_example.rb scale AMOUNT [FACTOR] [--clamp=<CLAMP>] [--notify]
|
|
|
398
440
|
|
|
399
441
|
Positional arguments:
|
|
400
442
|
AMOUNT [Integer] required Base amount to process
|
|
401
|
-
FACTOR
|
|
443
|
+
FACTOR [String] optional (default: 2)
|
|
402
444
|
|
|
403
445
|
Options:
|
|
404
446
|
--clamp=<CLAMP> [String] optional (default: nil)
|
|
405
447
|
--notify [Boolean] optional (default: false)
|
|
406
448
|
```
|
|
407
449
|
|
|
408
|
-
|
|
450
|
+
Only `AMOUNT` is documented, yet `factor`, `clamp`, and `notify` are presented
|
|
451
|
+
with inferred defaults and types.
|
|
409
452
|
|
|
410
|
-
|
|
453
|
+
Comments never add live parameters by themselves. Lines that reference
|
|
454
|
+
non-existent options (say `--ghost`) or positionals are shown verbatim in the
|
|
455
|
+
help's detail section instead of becoming real arguments, and strict mode warns
|
|
456
|
+
about positional mismatches. For a runnable mismatch demo:
|
|
457
|
+
`rubycli examples/fallback_example_with_extra_docs.rb scale --help`.
|
|
411
458
|
|
|
412
|
-
|
|
459
|
+
Run `rubycli --check path/to/script.rb` during development to lint
|
|
460
|
+
documentation drift — including undefined type labels and enum typos, with
|
|
461
|
+
DidYouMean suggestions — and pass `--strict` at runtime when invalid input
|
|
462
|
+
should abort instead of merely warning. `--check` still loads the target file to
|
|
463
|
+
inspect live signatures, so top-level code runs (`examples/hello_app_with_require.rb`
|
|
464
|
+
calls `Rubycli.run` on load, for instance); what it skips is executing the
|
|
465
|
+
selected command.
|
|
413
466
|
|
|
414
|
-
>
|
|
415
|
-
|
|
416
|
-
|
|
467
|
+
> `--strict` trusts whatever types/choices your comments spell out. Keep
|
|
468
|
+
> `rubycli --check` in CI so documentation typos are caught before production
|
|
469
|
+
> runs that rely on `--strict`.
|
|
417
470
|
|
|
418
471
|
## Argument parsing modes
|
|
419
472
|
|
|
420
473
|
### Default literal parsing
|
|
421
474
|
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
475
|
+
Arguments that look like structured literals (starting with `{`, `[`, quotes,
|
|
476
|
+
or YAML markers) are parsed with `Psych.safe_load`, so
|
|
477
|
+
`--names='["Alice","Bob"]'` or `--config='{foo: 1}'` arrive as native arrays
|
|
478
|
+
and hashes without extra flags. Plain strings like `1,2,3` stay untouched at
|
|
479
|
+
this stage (a later pass normalises them into arrays when the docs declare
|
|
480
|
+
`String[]` or `TAG...`), and unsupported constructs fall back to the original
|
|
481
|
+
text, so `"2024-01-01"` remains a string and malformed payloads still reach
|
|
482
|
+
your method instead of killing the run.
|
|
425
483
|
|
|
426
|
-
|
|
484
|
+
When an argument is documented as a plain `[String]`, the documented conversion
|
|
485
|
+
wins over literal parsing and the raw token is handed over verbatim — quote
|
|
486
|
+
characters included. `--prefix '"quoted"'` therefore arrives as `"quoted"` with
|
|
487
|
+
the quotes, while an undocumented parameter would receive `quoted`.
|
|
427
488
|
|
|
428
|
-
|
|
429
|
-
rubycli -j my_cli.rb MyCLI run '["--config", "{\"foo\":1}"]'
|
|
430
|
-
```
|
|
489
|
+
### JSON mode (`--json-args` / `-j`)
|
|
431
490
|
|
|
432
|
-
|
|
491
|
+
Parses subsequent arguments strictly as JSON. YAML-only syntax is rejected and
|
|
492
|
+
invalid payloads raise `JSON::ParserError` — for callers who want explicit
|
|
493
|
+
failures instead of silent fallbacks. Programmatic equivalent:
|
|
494
|
+
`Rubycli.with_json_mode(true) { ... }`.
|
|
433
495
|
|
|
434
|
-
|
|
496
|
+
### Eval mode (`--eval-args` / `-e`, `--eval-lax` / `-E`)
|
|
435
497
|
|
|
436
|
-
|
|
498
|
+
Evaluates each argument as a Ruby expression before it is forwarded, which is
|
|
499
|
+
handy for objects that are awkward as JSON — symbol arrays, ranges, inline
|
|
500
|
+
math:
|
|
437
501
|
|
|
438
502
|
```bash
|
|
439
|
-
|
|
503
|
+
# symbols and %w literals reach the method as real objects
|
|
504
|
+
rubycli -e --new='%w[x y]' examples/new_mode_runner.rb run --mode ':reverse'
|
|
505
|
+
#=> ["y", "x"]
|
|
506
|
+
|
|
507
|
+
# inline math is evaluated before the documented type conversion runs
|
|
508
|
+
rubycli -e examples/documentation_style_showcase.rb canonical '"Foo"' '2*3'
|
|
509
|
+
#=> {"style": "canonical", "subject": "Foo", "count": 6, ...}
|
|
440
510
|
```
|
|
441
511
|
|
|
442
|
-
Under
|
|
512
|
+
Under `--eval-args` **every** argument must be valid Ruby, so a bare word such
|
|
513
|
+
as `--mode summary` aborts; write `':summary'` (or `'"summary"'`) instead, or
|
|
514
|
+
switch to `--eval-lax` below.
|
|
515
|
+
|
|
516
|
+
Evaluation happens inside an isolated binding
|
|
517
|
+
(`Object.new.instance_eval { binding }`). All eval arguments in one Runner
|
|
518
|
+
execution, including `--new=VALUE` constructor arguments and the selected
|
|
519
|
+
command's arguments, share that binding; it is discarded after the execution.
|
|
520
|
+
Treat this as unsafe input: do not enable it for untrusted callers.
|
|
521
|
+
Programmatic equivalent: `Rubycli.with_eval_mode(true) { ... }`.
|
|
443
522
|
|
|
444
|
-
|
|
523
|
+
`--eval-lax` / `-E` behaves like `--eval-args`, but tokens that fail to parse
|
|
524
|
+
as Ruby (for example a bare `https://example.com`) produce a warning and are
|
|
525
|
+
forwarded as the original string — convenient for mixing expressions like
|
|
526
|
+
`60*60*24*14` with plain values:
|
|
445
527
|
|
|
446
528
|
```bash
|
|
447
|
-
rubycli -E
|
|
448
|
-
|
|
449
|
-
|
|
529
|
+
rubycli -E examples/hello_app.rb greet https://example.com
|
|
530
|
+
#=> [WARN] Failed to evaluate argument as Ruby (...). Passing it through because --eval-lax is enabled.
|
|
531
|
+
#=> Hello, https://example.com!
|
|
450
532
|
```
|
|
451
533
|
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
`--json-args`/`-j` cannot be combined with either `--eval-args`/`-e` or `--eval-lax`/`-E`; Rubycli will raise an error if both are present. Both modes augment the default literal parsing, so you can pick either strict JSON or one of the Ruby eval variants when the defaults are not enough.
|
|
534
|
+
`--json-args` cannot be combined with either eval variant; Rubycli raises an
|
|
535
|
+
error if both are present.
|
|
455
536
|
|
|
456
537
|
## Pre-script bootstrap
|
|
457
538
|
|
|
458
|
-
|
|
539
|
+
`--pre-script SRC` (alias: `--init`) runs arbitrary Ruby before commands are
|
|
540
|
+
resolved, inside an isolated binding with these locals pre-populated:
|
|
459
541
|
|
|
460
|
-
- `target`
|
|
461
|
-
- `current` / `instance`
|
|
542
|
+
- `target` — the original class or module (before `--new` instantiation)
|
|
543
|
+
- `current` / `instance` — the object that would otherwise be exposed
|
|
462
544
|
|
|
463
|
-
The last evaluated value becomes the new public target
|
|
545
|
+
The last evaluated value becomes the new public target (`nil` keeps the
|
|
546
|
+
previous object). `SRC` can be inline Ruby or a file path.
|
|
464
547
|
|
|
465
|
-
|
|
548
|
+
Example — replace the `--new`-built instance with a hand-built one:
|
|
466
549
|
|
|
467
550
|
```bash
|
|
468
|
-
rubycli --pre-script '
|
|
469
|
-
|
|
551
|
+
rubycli --pre-script 'NewModeRunner.new(%w[a b c], options: {from: :pre})' \
|
|
552
|
+
examples/new_mode_runner.rb run --mode summary
|
|
470
553
|
```
|
|
471
554
|
|
|
472
|
-
|
|
555
|
+
## Flags and environment variables
|
|
473
556
|
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
557
|
+
| Flag / Env | Description | Default |
|
|
558
|
+
| ---------- | ----------- | ------- |
|
|
559
|
+
| `--auto-target` / `-a`, `RUBYCLI_AUTO_TARGET=auto` | Auto-select the target constant when the file name does not match | `strict` |
|
|
560
|
+
| `--new[=VALUE]` / `-n[=VALUE]` | Instantiate the class before resolving commands; `VALUE` feeds the constructor's first parameter | off |
|
|
561
|
+
| `--pre-script SRC` / `--init SRC` | Run Ruby code to build/replace the exposed object | off |
|
|
562
|
+
| `--check` / `-c` | Lint documentation/comments without executing commands | off |
|
|
563
|
+
| `--strict` | Enforce documented types/choices; invalid input aborts | off |
|
|
564
|
+
| `--json-args` / `-j` | Parse arguments strictly as JSON | off |
|
|
565
|
+
| `--eval-args` / `-e`, `--eval-lax` / `-E` | Evaluate arguments as Ruby (lax: fall back to the raw string) | off |
|
|
566
|
+
| `--help` / `-h` / `help` | Print the `rubycli` usage message | — |
|
|
567
|
+
| `--print-result`, `RUBYCLI_PRINT_RESULT=true` | Print command return values. The bundled `rubycli` executable already does this, so the flag matters only when you embed `Rubycli.run` yourself | on for `rubycli`, off for `Rubycli.run` |
|
|
568
|
+
| `RUBYCLI_DEBUG=true` | Print debug logs | `false` |
|
|
569
|
+
| `RUBYCLI_ALLOW_PARAM_COMMENT=OFF` | Report YARD `@param` lines as issues during `rubycli --check` (no effect on normal runs) | `ON` |
|
|
570
|
+
|
|
571
|
+
## Library helpers
|
|
572
|
+
|
|
573
|
+
- `Rubycli.parse_arguments(argv, method)` — parse argv with comment metadata
|
|
574
|
+
- `Rubycli.available_commands(target)` — list CLI-exposable methods
|
|
575
|
+
- `Rubycli.usage_for_method(name, method)` — render usage for a single method
|
|
576
|
+
- `Rubycli.method_description(method)` — fetch structured documentation info
|
|
577
|
+
|
|
578
|
+
## How it differs from Python Fire
|
|
579
|
+
|
|
580
|
+
- **Comment-aware help** — doc comments enrich the help, but the live method
|
|
581
|
+
signature stays the ultimate authority.
|
|
582
|
+
- **Type-aware parsing** — placeholder syntax and YARD tags coerce arguments to
|
|
583
|
+
booleans, arrays, numerics, and more without additional code.
|
|
584
|
+
- **Two-stage validation** — `--check` lints documentation drift without
|
|
585
|
+
executing commands; `--strict` turns documented types/choices into
|
|
586
|
+
enforceable runtime contracts.
|
|
587
|
+
- **Ruby-centric** — keyword arguments, block documentation (`@yield*` tags),
|
|
588
|
+
and `RUBYCLI_*` environment toggles.
|
|
589
|
+
|
|
590
|
+
| Capability | Python Fire | Rubycli |
|
|
591
|
+
| ---------- | ----------- | ------- |
|
|
592
|
+
| Attribute traversal | Recursively exposes attributes/properties | Exposes public methods on the target; no implicit traversal |
|
|
593
|
+
| Constructor handling | Prompts for `__init__` args automatically | `--new` instantiates; constructor args via `--new=VALUE`, richer wiring via pre-scripts |
|
|
594
|
+
| Interactive shell | Fire-specific REPL when invoked without a command | No interactive shell; strictly command execution |
|
|
595
|
+
| Input discovery | Pure reflection, no doc comments | Doc comments drive option names, placeholders, and validation |
|
|
596
|
+
| Data structures | Dicts/lists become subcommands | Class/module methods only; no automatic dict/list expansion |
|
|
597
|
+
|
|
598
|
+
## Project philosophy
|
|
599
|
+
|
|
600
|
+
- **Convenience first** — wrap existing Ruby scripts with almost no manual
|
|
601
|
+
plumbing. Fidelity with Python Fire is not a goal; missing Fire features are
|
|
602
|
+
generally by design.
|
|
603
|
+
- **Method definitions first, comments augment** — signatures determine what is
|
|
604
|
+
exposed and what is required; comments refine types, help text, and
|
|
605
|
+
validation.
|
|
606
|
+
- **Maintenance** — much of the implementation was generated with AI
|
|
607
|
+
assistance. The project is no longer maintained; see
|
|
608
|
+
[Project status](#project-status).
|
|
609
|
+
|
|
610
|
+
## Bundled examples
|
|
611
|
+
|
|
612
|
+
- `examples/hello_app.rb` / `examples/hello_app_with_docs.rb` — minimal
|
|
613
|
+
module-function variants, without and with docs
|
|
614
|
+
- `examples/hello_app_with_require.rb` — embedded `Rubycli.run`
|
|
615
|
+
- `examples/typed_arguments_demo.rb` — stdlib type coercions
|
|
616
|
+
(Date/Time/BigDecimal/Pathname)
|
|
617
|
+
- `examples/strict_choices_demo.rb` — literal enumerations and `--strict`
|
|
618
|
+
- `examples/new_mode_runner.rb` — instance-only class initialized via
|
|
619
|
+
`--new=VALUE`
|
|
620
|
+
- `examples/documentation_style_showcase.rb` — every comment notation in one
|
|
621
|
+
script
|
|
622
|
+
- `examples/fallback_example.rb` / `examples/fallback_example_with_extra_docs.rb`
|
|
623
|
+
— signature fallback and doc-mismatch demos (these two intentionally fail
|
|
624
|
+
`rubycli --check`)
|
|
625
|
+
- `examples/multi_constant_runner.rb` / `examples/mismatched_constant_runner.rb`
|
|
626
|
+
— constant selection: several candidates in one file, and a file whose
|
|
627
|
+
constant does not match its name
|
|
628
|
+
|
|
629
|
+
The commands in this README assume you run them from the repository root. The
|
|
630
|
+
same files ship inside the gem, so after `gem install rubycli` you can locate
|
|
631
|
+
them with `gem contents rubycli`.
|
|
632
|
+
|
|
633
|
+
## Development
|
|
480
634
|
|
|
481
635
|
```bash
|
|
482
|
-
|
|
483
|
-
|
|
636
|
+
bundle install # minitest, rake, rubocop — Rubycli itself has no runtime dependencies
|
|
637
|
+
bundle exec rake # test suite + RuboCop
|
|
484
638
|
```
|
|
485
639
|
|
|
486
|
-
|
|
640
|
+
Individual tasks:
|
|
487
641
|
|
|
488
|
-
|
|
642
|
+
- `bundle exec rake test` — Minitest suite, including subprocess tests that drive
|
|
643
|
+
the real `exe/rubycli`
|
|
644
|
+
- `bundle exec rake lint` — RuboCop; `.rubocop_todo.yml` tracks the offenses that
|
|
645
|
+
are not fixed yet (mostly method-length metrics in the parsers)
|
|
646
|
+
- `bundle exec rake coverage` — the suite plus the repository coverage thresholds
|
|
647
|
+
(90% overall line coverage, 70% branch coverage, and 90% coverage of executable
|
|
648
|
+
lines changed from `origin/main`)
|
|
489
649
|
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
| `RUBYCLI_DEBUG=true` | Print debug logs | `false` |
|
|
493
|
-
| `--check` | Validate documentation/comments without executing commands | `off` |
|
|
494
|
-
| `--strict` | Enforce documented choices/types; invalid input aborts | `off` |
|
|
495
|
-
| `RUBYCLI_ALLOW_PARAM_COMMENT=OFF` | Disable legacy `@param` lines (defaults to on today for compatibility) | `ON` |
|
|
650
|
+
The coverage gate is dependency-free, so `ruby -Ilib:test test/coverage_runner.rb`
|
|
651
|
+
also works without Bundler.
|
|
496
652
|
|
|
497
|
-
##
|
|
653
|
+
## License
|
|
498
654
|
|
|
499
|
-
|
|
500
|
-
- `Rubycli.available_commands(target)` – list CLI exposable methods
|
|
501
|
-
- `Rubycli.usage_for_method(name, method)` – render usage for a single method
|
|
502
|
-
- `Rubycli.method_description(method)` – fetch structured documentation info
|
|
655
|
+
MIT. See [LICENSE](LICENSE).
|
|
503
656
|
|
|
504
|
-
Feedback and issues are welcome
|
|
657
|
+
Feedback and issues are welcome.
|