rubycli 0.1.7 → 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 +77 -2
- data/LICENSE +1 -1
- data/README.ja.md +357 -252
- data/README.md +386 -250
- 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 +295 -96
- data/lib/rubycli/cli.rb +26 -30
- data/lib/rubycli/command_line.rb +151 -86
- data/lib/rubycli/constant_capture.rb +563 -6
- data/lib/rubycli/documentation/metadata_parser.rb +108 -74
- 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 -456
- 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
|
-
|
|
98
|
+
`rubycli examples/hello_app.rb --help` prints the same summary as invoking it
|
|
99
|
+
without a command.
|
|
58
100
|
|
|
59
|
-
### 2. Add
|
|
101
|
+
### 2. Add doc comments for typed options
|
|
60
102
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
**Concise placeholder style**
|
|
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,95 +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. When your constructor needs arguments, pass them inline with `--new=VALUE` (safe YAML/JSON-like parsing by default; `--json-args` for strict JSON, `--eval-args` / `--eval-lax` for Ruby literals). Any comments on `initialize` are respected for type coercion just like regular CLI methods.
|
|
167
|
-
|
|
168
|
-
> Hint: Single values should be passed as `--new=value` so they aren’t mistaken for the next path/command. Space-separated single tokens like `--new 1` may be treated as the following path unless they look obviously structured.
|
|
169
|
-
|
|
170
|
-
## Project Philosophy
|
|
171
|
-
|
|
172
|
-
- **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.
|
|
173
|
-
- **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.”
|
|
174
|
-
- **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.
|
|
175
|
-
- **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.
|
|
176
|
-
|
|
177
|
-
## Features
|
|
178
|
-
|
|
179
|
-
- Comment-aware CLI generation with both YARD-style tags and concise placeholders
|
|
180
|
-
- Automatic option signature inference (`NAME [Type] Description…`) without extra DSLs
|
|
181
|
-
- Safe literal parsing out of the box (arrays / hashes / booleans) with opt-in strict JSON and Ruby eval modes
|
|
182
|
-
- Optional pre-script hook (`--pre-script` / `--init`) to evaluate Ruby and expose the resulting object
|
|
183
|
-
- Dedicated CLI flags for quality gates: `--check` lints documentation/comments without running commands, and `--strict` treats documented types/choices as hard requirements
|
|
184
|
-
- Example `examples/new_mode_runner.rb` demonstrates instance-only classes with `--new=VALUE` constructor arguments, eval/JSON modes, and a pre-script initialization pattern.
|
|
185
|
-
|
|
186
|
-
### Examples
|
|
187
|
-
|
|
188
|
-
- `examples/hello_app.rb` / `examples/hello_app_with_docs.rb`: minimal module-function variants, with and without docs
|
|
189
|
-
- `examples/typed_arguments_demo.rb`: stdlib type coercions (Date/Time/BigDecimal/Pathname)
|
|
190
|
-
- `examples/strict_choices_demo.rb`: literal enumerations and `--strict`
|
|
191
|
-
- `examples/new_mode_runner.rb`: instance-only class initialized via `--new=VALUE` with eval/JSON/pre-script combinations
|
|
192
|
-
|
|
193
|
-
> 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`.
|
|
194
|
-
|
|
195
|
-
## How it differs from Python Fire
|
|
196
|
-
|
|
197
|
-
- **Comment-aware help** – Rubycli leans on doc comments when present but still reflects the live method signature, keeping code as the ultimate authority.
|
|
198
|
-
- **Type-aware parsing** – Placeholder syntax (`NAME [String]`) and YARD tags let Rubycli coerce arguments to booleans, arrays, numerics, etc. without additional code.
|
|
199
|
-
- **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.
|
|
200
|
-
- **Ruby-centric tooling** – Supports Ruby-specific conventions such as optional keyword arguments, block documentation (`@yield*` tags), and `RUBYCLI_*` environment toggles.
|
|
201
|
-
|
|
202
|
-
| Capability | Python Fire | Rubycli |
|
|
203
|
-
| ---------- | ----------- | -------- |
|
|
204
|
-
| Attribute traversal | Recursively exposes attributes/properties on demand | Exposes public methods defined on the target; no implicit traversal |
|
|
205
|
-
| Constructor handling | Automatically prompts for `__init__` args when instantiating classes | `--new` instantiates and accepts constructor arguments via `--new=VALUE` (safe YAML/JSON-like parsing by default; `--json-args` for strict JSON, `--eval-args` / `--eval-lax` for Ruby literals). Use pre-scripts or your own factories for more complex wiring. |
|
|
206
|
-
| Interactive shell | Offers Fire-specific REPL when invoked without command | No interactive shell mode; strictly command execution |
|
|
207
|
-
| Input discovery | Pure reflection, no doc comments required | Doc comments drive option names, placeholders, and validation |
|
|
208
|
-
| Data structures | Dictionaries / lists become subcommands by default | Focused on class or module methods; no automatic dict/list expansion |
|
|
209
|
-
|
|
210
|
-
#### Example commands
|
|
211
|
-
|
|
212
|
-
- `rubycli examples/new_mode_runner.rb run --new='["a","b","c"]' --mode reverse`
|
|
213
|
-
- `rubycli --json-args --new='["x","y"]' examples/new_mode_runner.rb run --mode summary --options '{"source":"json"}'`
|
|
214
|
-
- `rubycli --eval-args --new='["x","y"]' examples/new_mode_runner.rb run --mode summary --options '{tags: [:a, :b]}'`
|
|
215
|
-
- `rubycli --pre-script 'NewModeRunner.new(%w[a b c], options: {from: :pre})' examples/new_mode_runner.rb run --mode summary`
|
|
216
|
-
|
|
217
|
-
## Installation
|
|
218
|
-
|
|
219
|
-
Rubycli is published on RubyGems.
|
|
220
|
-
|
|
221
|
-
```bash
|
|
222
|
-
gem install rubycli
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
Bundler example:
|
|
226
|
-
|
|
227
|
-
```ruby
|
|
228
|
-
# Gemfile
|
|
229
|
-
gem "rubycli"
|
|
230
|
-
```
|
|
182
|
+
### 3. Optional: embed the runner in your script
|
|
231
183
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
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`):
|
|
235
186
|
|
|
236
187
|
```ruby
|
|
237
188
|
# hello_app_with_require.rb
|
|
@@ -254,131 +205,219 @@ end
|
|
|
254
205
|
Rubycli.run(HelloApp)
|
|
255
206
|
```
|
|
256
207
|
|
|
257
|
-
Run it:
|
|
258
|
-
|
|
259
208
|
```bash
|
|
260
|
-
ruby examples/hello_app_with_require.rb greet Taro
|
|
261
|
-
#=> Hello, Taro!
|
|
262
|
-
|
|
263
209
|
ruby examples/hello_app_with_require.rb greet Taro --shout
|
|
264
210
|
#=> HELLO, TARO!
|
|
265
211
|
```
|
|
266
212
|
|
|
267
|
-
|
|
213
|
+
When you run a file through the bundled `rubycli` executable instead, return
|
|
214
|
+
values are printed automatically.
|
|
268
215
|
|
|
269
|
-
|
|
270
|
-
rubycli
|
|
271
|
-
|
|
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
|
|
272
221
|
|
|
273
|
-
|
|
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:
|
|
274
225
|
|
|
275
|
-
|
|
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`.
|
|
236
|
+
|
|
237
|
+
```bash
|
|
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`):
|
|
276
274
|
|
|
277
275
|
```bash
|
|
278
|
-
rubycli
|
|
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
|
+
]
|
|
279
285
|
```
|
|
280
286
|
|
|
281
|
-
|
|
287
|
+
Return values are rendered as pretty-printed JSON when a command returns a
|
|
288
|
+
structure instead of printing it.
|
|
282
289
|
|
|
283
290
|
## Comment syntax
|
|
284
291
|
|
|
285
|
-
Rubycli parses a hybrid format
|
|
292
|
+
Rubycli parses a hybrid format — familiar YARD tags or short forms:
|
|
286
293
|
|
|
287
294
|
| Purpose | YARD-compatible | Rubycli style |
|
|
288
295
|
| ------- | --------------- | ------------- |
|
|
289
296
|
| Positional argument | `@param name [Type] Description` | `NAME [Type] Description` |
|
|
290
|
-
| Keyword option |
|
|
297
|
+
| Keyword option | same | `--flag -f VALUE [Type] Description` |
|
|
291
298
|
| Return value | `@return [Type] Description` | `=> [Type] Description` |
|
|
292
299
|
|
|
293
|
-
Short options are optional and order-independent
|
|
300
|
+
Short options are optional and order-independent; these are equivalent:
|
|
294
301
|
|
|
295
302
|
- `--flag -f VALUE [Type] Description`
|
|
296
303
|
- `--flag VALUE [Type] Description`
|
|
297
304
|
- `-f --flag VALUE [Type] Description`
|
|
298
305
|
|
|
299
|
-
|
|
306
|
+
Types can be written as `[String]` or `(String)`, and unions as
|
|
307
|
+
`(String, nil)`.
|
|
300
308
|
|
|
301
309
|
### Alternate placeholder notations
|
|
302
310
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
- Angle brackets for user input: `--flag <value>` or `NAME [<value>]`
|
|
306
|
-
- Inline equals for long options: `--flag=<value>`
|
|
307
|
-
- Trailing ellipsis for repeated values: `VALUE...` or `<value>...`
|
|
308
|
-
|
|
309
|
-
The CLI treats `--flag VALUE`, `--flag <value>`, and `--flag=<value>` identically at runtime—document with whichever variant your team prefers. Optional placeholders like `[VALUE]` or `[VALUE...]` let Rubycli infer boolean flags, optional values, and list coercion. When you omit the placeholder entirely (for example `--quiet`), Rubycli infers a Boolean flag automatically.
|
|
311
|
+
These are understood both when parsing comments and when rendering help:
|
|
310
312
|
|
|
311
|
-
|
|
313
|
+
- Angle brackets: `--flag <value>`, `NAME [<value>]`
|
|
314
|
+
- Inline equals: `--flag=<value>`
|
|
315
|
+
- Trailing ellipsis for repeated values: `VALUE...`, `<value>...`
|
|
312
316
|
|
|
313
|
-
|
|
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.
|
|
314
321
|
|
|
315
|
-
|
|
322
|
+
Inference rules when annotations are partial:
|
|
316
323
|
|
|
317
|
-
|
|
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.
|
|
318
329
|
|
|
319
|
-
|
|
330
|
+
### Arrays and repeated values
|
|
320
331
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
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"]'`.
|
|
325
341
|
|
|
326
342
|
### Literal choices and enums
|
|
327
343
|
|
|
328
|
-
|
|
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.
|
|
329
352
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
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.
|
|
333
356
|
|
|
334
357
|
```bash
|
|
335
|
-
#
|
|
336
|
-
|
|
337
|
-
#=> [WARN] format=json
|
|
338
|
-
|
|
339
|
-
# the same command with --strict will abort when values drift
|
|
340
|
-
ruby -Ilib exe/rubycli --strict examples/strict_choices_demo.rb report debug
|
|
341
|
-
#=> Rubycli::ArgumentError: Value "debug" for LEVEL is not allowed: allowed values are :info, :warn, :error
|
|
342
|
-
```
|
|
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)
|
|
343
361
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
#=> [WARN] format=text
|
|
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)
|
|
348
365
|
|
|
349
|
-
|
|
350
|
-
|
|
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")
|
|
351
369
|
```
|
|
352
370
|
|
|
371
|
+
Literal enums currently apply to each scalar argument; combined literal arrays
|
|
372
|
+
such as `[%i[foo bar][]]` are not supported.
|
|
373
|
+
|
|
353
374
|
### Standard library type hints
|
|
354
375
|
|
|
355
|
-
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:
|
|
356
380
|
|
|
357
381
|
```bash
|
|
358
382
|
# see examples/typed_arguments_demo.rb
|
|
359
|
-
|
|
383
|
+
rubycli examples/typed_arguments_demo.rb ingest \
|
|
360
384
|
--date 2024-12-25 \
|
|
361
385
|
--moment 2024-12-25T10:00:00Z \
|
|
362
386
|
--budget 123.45 \
|
|
363
387
|
--input ./data/input.csv
|
|
364
388
|
```
|
|
365
389
|
|
|
366
|
-
|
|
390
|
+
Every option there has a default, so you can also experiment one at a time
|
|
391
|
+
(`... ingest --budget 999.99`).
|
|
367
392
|
|
|
368
|
-
|
|
393
|
+
Other YARD tags such as `@example`, `@raise`, `@see`, and `@deprecated` are
|
|
394
|
+
currently ignored by the help renderer.
|
|
369
395
|
|
|
370
|
-
|
|
396
|
+
> To explore every notation in one script, try
|
|
397
|
+
> `rubycli examples/documentation_style_showcase.rb canonical --help` and the
|
|
398
|
+
> other showcase commands.
|
|
371
399
|
|
|
372
|
-
|
|
400
|
+
### Notes on YARD-style comments
|
|
373
401
|
|
|
374
|
-
|
|
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.
|
|
375
413
|
|
|
376
414
|
### When docs are missing or incomplete
|
|
377
415
|
|
|
378
|
-
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:
|
|
379
418
|
|
|
380
419
|
```ruby
|
|
381
|
-
# fallback_example.rb
|
|
420
|
+
# examples/fallback_example.rb
|
|
382
421
|
module FallbackExample
|
|
383
422
|
module_function
|
|
384
423
|
|
|
@@ -392,20 +431,6 @@ module FallbackExample
|
|
|
392
431
|
end
|
|
393
432
|
```
|
|
394
433
|
|
|
395
|
-
```bash
|
|
396
|
-
rubycli examples/fallback_example.rb
|
|
397
|
-
```
|
|
398
|
-
|
|
399
|
-
```text
|
|
400
|
-
Usage: fallback_example.rb COMMAND [arguments]
|
|
401
|
-
|
|
402
|
-
Available commands:
|
|
403
|
-
Class methods:
|
|
404
|
-
scale AMOUNT [<FACTOR>] [--clamp=<value>] [--notify]
|
|
405
|
-
|
|
406
|
-
Detailed command help: fallback_example.rb COMMAND help
|
|
407
|
-
```
|
|
408
|
-
|
|
409
434
|
```bash
|
|
410
435
|
rubycli examples/fallback_example.rb scale --help
|
|
411
436
|
```
|
|
@@ -415,107 +440,218 @@ Usage: fallback_example.rb scale AMOUNT [FACTOR] [--clamp=<CLAMP>] [--notify]
|
|
|
415
440
|
|
|
416
441
|
Positional arguments:
|
|
417
442
|
AMOUNT [Integer] required Base amount to process
|
|
418
|
-
FACTOR
|
|
443
|
+
FACTOR [String] optional (default: 2)
|
|
419
444
|
|
|
420
445
|
Options:
|
|
421
446
|
--clamp=<CLAMP> [String] optional (default: nil)
|
|
422
447
|
--notify [Boolean] optional (default: false)
|
|
423
448
|
```
|
|
424
449
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
#### What if the docs mention arguments that do not exist?
|
|
450
|
+
Only `AMOUNT` is documented, yet `factor`, `clamp`, and `notify` are presented
|
|
451
|
+
with inferred defaults and types.
|
|
428
452
|
|
|
429
|
-
|
|
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`.
|
|
430
458
|
|
|
431
|
-
|
|
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.
|
|
432
466
|
|
|
433
|
-
|
|
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`.
|
|
434
470
|
|
|
435
471
|
## Argument parsing modes
|
|
436
472
|
|
|
437
473
|
### Default literal parsing
|
|
438
474
|
|
|
439
|
-
|
|
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.
|
|
440
483
|
|
|
441
|
-
|
|
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`.
|
|
442
488
|
|
|
443
|
-
|
|
489
|
+
### JSON mode (`--json-args` / `-j`)
|
|
444
490
|
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
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) { ... }`.
|
|
448
495
|
|
|
449
|
-
|
|
496
|
+
### Eval mode (`--eval-args` / `-e`, `--eval-lax` / `-E`)
|
|
450
497
|
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
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:
|
|
454
501
|
|
|
455
502
|
```bash
|
|
456
|
-
|
|
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, ...}
|
|
457
510
|
```
|
|
458
511
|
|
|
459
|
-
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.
|
|
460
515
|
|
|
461
|
-
|
|
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) { ... }`.
|
|
522
|
+
|
|
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:
|
|
462
527
|
|
|
463
528
|
```bash
|
|
464
|
-
rubycli -E
|
|
465
|
-
|
|
466
|
-
|
|
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!
|
|
467
532
|
```
|
|
468
533
|
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
`--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.
|
|
472
536
|
|
|
473
537
|
## Pre-script bootstrap
|
|
474
538
|
|
|
475
|
-
|
|
539
|
+
`--pre-script SRC` (alias: `--init`) runs arbitrary Ruby before commands are
|
|
540
|
+
resolved, inside an isolated binding with these locals pre-populated:
|
|
476
541
|
|
|
477
|
-
- `target`
|
|
478
|
-
- `current` / `instance`
|
|
542
|
+
- `target` — the original class or module (before `--new` instantiation)
|
|
543
|
+
- `current` / `instance` — the object that would otherwise be exposed
|
|
479
544
|
|
|
480
|
-
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.
|
|
481
547
|
|
|
482
|
-
|
|
548
|
+
Example — replace the `--new`-built instance with a hand-built one:
|
|
483
549
|
|
|
484
550
|
```bash
|
|
485
|
-
rubycli --pre-script '
|
|
486
|
-
|
|
551
|
+
rubycli --pre-script 'NewModeRunner.new(%w[a b c], options: {from: :pre})' \
|
|
552
|
+
examples/new_mode_runner.rb run --mode summary
|
|
487
553
|
```
|
|
488
554
|
|
|
489
|
-
|
|
555
|
+
## Flags and environment variables
|
|
490
556
|
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
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
|
|
497
634
|
|
|
498
635
|
```bash
|
|
499
|
-
|
|
500
|
-
|
|
636
|
+
bundle install # minitest, rake, rubocop — Rubycli itself has no runtime dependencies
|
|
637
|
+
bundle exec rake # test suite + RuboCop
|
|
501
638
|
```
|
|
502
639
|
|
|
503
|
-
|
|
640
|
+
Individual tasks:
|
|
504
641
|
|
|
505
|
-
|
|
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`)
|
|
506
649
|
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
| `RUBYCLI_DEBUG=true` | Print debug logs | `false` |
|
|
510
|
-
| `--check` | Validate documentation/comments without executing commands | `off` |
|
|
511
|
-
| `--strict` | Enforce documented choices/types; invalid input aborts | `off` |
|
|
512
|
-
| `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.
|
|
513
652
|
|
|
514
|
-
##
|
|
653
|
+
## License
|
|
515
654
|
|
|
516
|
-
|
|
517
|
-
- `Rubycli.available_commands(target)` – list CLI exposable methods
|
|
518
|
-
- `Rubycli.usage_for_method(name, method)` – render usage for a single method
|
|
519
|
-
- `Rubycli.method_description(method)` – fetch structured documentation info
|
|
655
|
+
MIT. See [LICENSE](LICENSE).
|
|
520
656
|
|
|
521
|
-
Feedback and issues are welcome
|
|
657
|
+
Feedback and issues are welcome.
|