rubycli 0.1.4 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a71a438637363ea54e22377b645dc99a26a0c91692571bf57a68368403e32308
4
- data.tar.gz: 367b354b2ffde5ee80e7ee3ee5b2858f15cbf8097cc8346fd812b780f41443e2
3
+ metadata.gz: 521eac399843d8fe002c1017b24b0cf72644f179460d3a599a1b9bf9d0949d7e
4
+ data.tar.gz: d245d65f31c08f15c0f9bad5d4e13e3d7cb1785936772ab6a83887cd4fdf4564
5
5
  SHA512:
6
- metadata.gz: 5eb055a5cbaa3daf0d311b67922a0c9bb7dbb8a75c2844524dc21f5faed232f560c8f1aaea6caf96737fea0b979625813b1ea5cc6c589ecee405b994b07ee16f
7
- data.tar.gz: f64107c28083a96674970f8414090e47b77a749f8d3c9393ff9ca972a747ebe36a5da128d1c75a313ca570631436509392985477d1eefe271722eb4b046c69a8
6
+ metadata.gz: 286af4633230ddd40c39e40c2ec92f810bd47cc533c1d578dc42178179552518bfc057f992beef340cc4a34592c603d0ddc6d10eef1df928ce83be383cd9857c
7
+ data.tar.gz: 82e587aac72882cb1b3e317d20d2dc37c54ed8e927fc39ffa9d28dd871d77b05c6d2fc64ad13dc5e3fe7c903b6f5312dfa0b34e9e46391e66788435286c909e9
data/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.1.6] - 2025-11-11
4
+
5
+ ### Changed
6
+ - `rubycli --check` now reports unknown type tokens and enumerated allowed values (with DidYouMean suggestions) instead of silently treating them as strings, while `--strict` continues to enforce the surviving annotations at runtime.
7
+
8
+ ## [0.1.5] - 2025-11-10
9
+
10
+ ### Added
11
+ - `rubycli --check` gained a short `-c` alias and refuses to run target commands while linting, making documentation checks easier to script.
12
+ - Bundled `examples/strict_choices_demo.rb` and `examples/typed_arguments_demo.rb` now illustrate literal choice validation and stdlib type coercions.
13
+
14
+ ### Changed
15
+ - Runtime validation now reads the documented literal choices and inferred types for both positional and keyword arguments; invalid values emit `[WARN] …` guidance by default and raise `Rubycli::ArgumentError` under `--strict` with friendly suggestions.
16
+ - Help output renders positional arguments and options as structured tables showing requirement level, types, defaults, and descriptions for quicker scanning.
17
+ - Documentation comments are aligned with the actual method signature, and mismatches surface with file/line context during `rubycli --check`.
18
+ - CLI warnings/errors are prefixed with `[WARN]` / `[ERROR]`, and the deprecated `--debug` flag was removed in favor of `RUBYCLI_DEBUG=true`.
19
+
20
+ ### Fixed
21
+ - `--check` now rejects forwarded CLI arguments as well as JSON/Eval modes, ensuring documentation linting never executes user code and always starts from a clean issue list.
22
+ - Placeholder parsing keeps option descriptions such as `--prefix` in the documentation showcase so README snippets and live behavior stay in sync.
23
+
3
24
  ## [0.1.4] - 2025-11-08
4
25
 
5
26
  ### Changed
@@ -7,6 +28,9 @@
7
28
 
8
29
  > _Note:_ 0.1.3 was yanked before general availability; consumers should upgrade directly to 0.1.4.
9
30
 
31
+ ### Documentation
32
+ - Clarified repeated-value guidance (type enforcement, eval mode workflows) and updated both READMEs to reflect the retirement of `(type: …)` annotations while preserving the historical changelog entry.
33
+
10
34
  ## [0.1.3] - 2025-11-08
11
35
 
12
36
  ### Added
data/README.ja.md CHANGED
@@ -33,7 +33,6 @@ Available commands:
33
33
  greet <NAME>
34
34
 
35
35
  Detailed command help: hello_app.rb COMMAND help
36
- Enable debug logging: --debug or RUBYCLI_DEBUG=true
37
36
  ```
38
37
 
39
38
  ```bash
@@ -107,7 +106,6 @@ Available commands:
107
106
  greet <NAME> [--shout]
108
107
 
109
108
  Detailed command help: hello_app_with_docs.rb COMMAND help
110
- Enable debug logging: --debug or RUBYCLI_DEBUG=true
111
109
  ```
112
110
 
113
111
  ```bash
@@ -158,13 +156,13 @@ Rubycli は「ファイル名を CamelCase にした定数」を公開対象だ
158
156
 
159
157
  大規模なコードベースでも安全側を保ちながら、どうしても自動選択したいときだけ 1 フラグで切り替えられます。
160
158
 
161
- > **インスタンスメソッド専用のクラスについて** – 公開メソッドがインスタンス側(`attr_reader` `def greet`)にしか無い場合は、`--new` を付けて事前にインスタンス化しないと CLI から呼び出せません。クラスメソッドを 1 つ用意するか、`--new` を明示して実行してください。
159
+ > **インスタンスメソッド専用のクラスについて** – 公開メソッドがインスタンス側(`def greet` など)にしか無い場合は、`--new` を付けて事前にインスタンス化しないと CLI から呼び出せません。クラスメソッドを 1 つ用意するか、`--new` を明示して実行してください。`--new` を付ければ `rubycli --help` でもインスタンスメソッドが一覧に現れ、`rubycli --check --new` でコメントの lint も実行できます。
162
160
 
163
161
  ## 開発方針
164
162
 
165
163
  - **便利さが最優先** – 既存の Ruby スクリプトを最小の手間で CLI 化できることを目的にしており、Python Fire の完全移植は目指していません。
166
164
  - **インスパイアであってポートではない** – アイデアの出自は Fire ですが、同等機能を揃える予定は基本的にありません。Fire 由来の未実装機能は仕様です。
167
- - **メソッド定義が土台、コメントが挙動を補強** – 公開メソッドのシグネチャが CLI に露出する範囲と必須/任意を決めますが、コメントに `TAG...` や `[Integer]` を書くと同じ引数でも配列化や型変換が行われます。コメントと実装のズレを観測したいときだけ `RUBYCLI_STRICT=ON` で厳格モードを有効化し、警告を受け取ります。
165
+ - **メソッド定義が土台、コメントが挙動を補強** – 公開メソッドのシグネチャが CLI に露出する範囲と必須/任意を決めますが、コメントに `TAG...` や `[Integer]` を書くと同じ引数でも配列化や型変換が行われます。さらに Rubycli は `--names='["Alice","Bob"]'` のような JSON/YAML らしい入力を自動的に安全なリテラルとして評価します。`rubycli --check パス/対象.rb` でコメントと実装のズレ(未定義の型ラベルや列挙値の誤記を含む)を DidYouMean の候補付きで検査し、通常実行時に `--strict` を付ければドキュメント通りでない入力をその場でエラーにできます。
168
166
  - **軽量メンテナンス** – 実装の多くは AI 支援で作られており、深い Ruby メタプログラミングを伴う大規模拡張は想定外です。Fire 互換を求める PR は事前相談をお願いします。
169
167
 
170
168
  ## 特徴
@@ -173,13 +171,15 @@ Rubycli は「ファイル名を CamelCase にした定数」を公開対象だ
173
171
  - YARD 形式と `NAME [Type] 説明…` の簡潔記法を同時サポート
174
172
  - 引数はデフォルトで安全なリテラルとして解釈し、必要に応じて厳格 JSON モードや Ruby eval モードを切り替え可能
175
173
  - `--pre-script`(エイリアス: `--init`)で任意の Ruby コードを評価し、その結果オブジェクトを公開
176
- - `RUBYCLI_STRICT=ON` で有効化できる厳格モードにより、コメントとシグネチャの矛盾を警告として検知可能
174
+ - `--check` でコメント整合性を lint、`--strict` で入力値をドキュメント通りに強制する二段構えのガード
175
+
176
+ > 補足: `--strict` はコメントに書かれた型/許可値をそのまま信頼して検証するため、コメントが誤記だと実行時には検出できません。CI では必ず `rubycli --check` を走らせ、`--strict` は「 lint を通過したドキュメントを本番で厳密に守る」用途に使ってください。
177
177
 
178
178
  ## Python Fire との違い
179
179
 
180
180
  - **コメント対応のヘルプ生成**: コメントがあればヘルプに反映しつつ、最終的な判断は常にライブなメソッド定義に基づきます。
181
181
  - **型に基づく解析**: `NAME [String]` や YARD タグから型を推論し、真偽値・配列・数値などを自動変換します。
182
- - **厳密な整合性チェック**: 厳格モードを有効にすれば、コメントとメソッド定義が食い違う際に警告を出して保守性を高められます。
182
+ - **厳密な整合性チェック**: `rubycli --check` でコメントと実装のズレ(未定義の型ラベルや列挙値の誤記など)をコード実行前に検査し、通常実行時に `--strict` を付ければドキュメントで宣言した型・許可値以外の入力を拒否できます。
183
183
  - **Ruby 向け拡張**: キーワード引数やブロック (`@yield*`) といった Ruby 固有の構文に合わせたパーサや `RUBYCLI_*` 環境変数を用意しています。
184
184
 
185
185
  | 機能 | Python Fire | Rubycli |
@@ -284,15 +284,62 @@ README のサンプルは既定スタイルとして大文字プレースホル
284
284
 
285
285
  > 補足: コメント内で任意引数を角括弧で表す必要はありません。Ruby 側のメソッドシグネチャから必須/任意は自動判定され、ヘルプ出力では Rubycli が適切に角括弧を追加します。
286
286
 
287
- 型ヒントは `[String]`, `(String)`, `(type: String)` のように角括弧・丸括弧・`type:` プレフィックスのいずれでも指定できます。複数型は `(String, nil)` `(type: String, nil)` のように列挙してください。
287
+ 型ヒントは `[String]` `(String)` のように角括弧/丸括弧で指定できます。複数型は `(String, nil)` のように列挙してください。
288
+
289
+ `VALUE...` のような繰り返し指定(`TAG...` など)や、`[String[]]` / `Array<String>` といった配列型の注釈が付いたオプションは配列として扱われます。JSON/YAML 形式のリスト(例: `--tags '["build","test"]'`)を渡すか、カンマ区切り文字列(`--tags "build,test"`)を渡すことで配列に変換されます。スペース区切りの複数値入力(`--tags build test`)にはまだ対応しておらず、繰り返し注記のないオプションは従来どおりスカラーとして扱われます。`--strict` 実行時は各要素の型も検証されるため、`[String[]]` と書かれているのに `--tags [1,2]` のような数値配列を渡すと即エラーになります。
288
290
 
289
- `VALUE...` のような繰り返し指定(`TAG...` など)や、`[String[]]` / `Array<String>` といった配列型の注釈が付いたオプションは配列として扱われます。JSON/YAML 形式のリスト(例: `--tags '["build","test"]'`)を渡すか、カンマ区切り文字列(`--tags "build,test"`)を渡すことで配列に変換されます。スペース区切りの複数値入力(`--tags build test`)にはまだ対応しておらず、繰り返し注記のないオプションは従来どおりスカラーとして扱われます。
291
+ JSON やカンマ区切りで表現しづらいシンボル配列・ハッシュなどを渡したい場合は eval モード(`--eval-args`/`-e` または `--eval-lax`/`-E`)を有効にし、ドキュメントで宣言した型に合わせた Ruby リテラルを渡してください。スペース区切りが未対応でも、安全に複数選択を指定できます(後述の eval 例を参照)。
290
292
 
291
293
  代表的な推論例:
292
294
 
293
295
  - `ARG1` のように型ラベルを省略したプレースホルダは既定で `String` として扱われます。
294
296
  - `--name ARG1` のようにオプションへプレースホルダだけを指定しても同じく `String` が推論されます。
295
297
  - `--verbose` のように値プレースホルダを省略したオプションは Boolean フラグとして扱われます。
298
+ - 位置引数を Boolean にしたい場合は必ず `[Boolean]` を明示してください。`NAME 説明` や `@param name 説明` のように型を省略すると、Ruby 側のデフォルト値に関わらず `String` とみなされます。
299
+
300
+ ### リテラル列挙による制約
301
+
302
+ `--format MODE [:json, :yaml, :auto]` や `LEVEL [:info, :warn]` のように型注釈内へ許容リテラルを列挙すると、ヘルプに選択肢を表示しつつ Rubycli が入力制約として解釈します。シンボル・文字列(裸の単語も可)・真偽値・数値・`nil` に対応し、型ヒントと混在させて `--channel TARGET [:stdout, :stderr, Boolean]` のような宣言も書けます。`%i[info warn]` / `%w[debug info]` などの短縮記法も展開されるため、`LEVEL %i[info warn]` でも同じ効果になります。通常実行では許可外の入力に警告を表示して続行し、`--strict` を付けた場合は `Rubycli::ArgumentError` を送出して即座に停止します。
303
+
304
+ > シンボルと文字列は厳密に区別されます。`[:info, :warn]` と書いた場合は `:info` のようにコロン付きで入力してください。`["info", "warn"]` を選んだ場合はプレーンな文字列のみ受け付けます。
305
+
306
+ > 列挙は各スカラー値に適用されます。`[Symbol[]]` のような配列注釈に対して「許可される組み合わせ」をリテラルで書く構文(例: `[%i[foo bar][]]`)は未サポートなので、必要に応じて文章で説明するか、eval モードで Ruby の配列を渡してください。
307
+
308
+ ```bash
309
+ # literal choice デモ (examples/strict_choices_demo.rb)
310
+ ruby examples/strict_choices_demo.rb report warn --format json
311
+ #=> [WARN] format=json
312
+
313
+ # --strict を付けると仕様外の値で即エラー
314
+ ruby -Ilib exe/rubycli --strict examples/strict_choices_demo.rb report debug
315
+ #=> Rubycli::ArgumentError: Value "debug" for LEVEL is not allowed: allowed values are :info, :warn, :error
316
+ ```
317
+
318
+ ```bash
319
+ # シンボル入力はコロンを付ける
320
+ ruby -Ilib exe/rubycli --strict examples/strict_choices_demo.rb report :warn
321
+ #=> [WARN] format=text
322
+
323
+ ruby -Ilib exe/rubycli --strict examples/strict_choices_demo.rb report warn
324
+ #=> Rubycli::ArgumentError: Value "warn" for LEVEL is not allowed: allowed values are :info, :warn, :error
325
+ ```
326
+
327
+ ### 標準ライブラリ型ヒント
328
+
329
+ コメントに `Date` や `Time`, `BigDecimal`, `Pathname` など標準ライブラリの型名を書けば、Rubycli が必要な `require` を行った上で CLI 引数をその型へ変換します。
330
+
331
+ ```bash
332
+ # examples/typed_arguments_demo.rb より
333
+ ruby examples/typed_arguments_demo.rb ingest \
334
+ --date 2024-12-25 \
335
+ --moment 2024-12-25T10:00:00Z \
336
+ --budget 123.45 \
337
+ --input ./data/input.csv
338
+ ```
339
+
340
+ ハンドラ側には `Date` / `Time` / `BigDecimal` / `Pathname` のインスタンスがそのまま渡るため、追加のパース処理は不要です。
341
+
342
+ 各オプションには既定値があるため、`ruby examples/typed_arguments_demo.rb ingest --budget 999.99` のように個別の型だけ試すこともできます。
296
343
 
297
344
  `@example` や `@raise`, `@see`, `@deprecated` などその他の YARD タグは、現状ヘルプ出力には反映されません。
298
345
 
@@ -331,7 +378,6 @@ Available commands:
331
378
  scale AMOUNT [<FACTOR>] [--clamp=<value>] [--notify]
332
379
 
333
380
  Detailed command help: fallback_example.rb COMMAND help
334
- Enable debug logging: --debug or RUBYCLI_DEBUG=true
335
381
  ```
336
382
 
337
383
  ```bash
@@ -350,7 +396,7 @@ Options:
350
396
  --notify [Boolean] optional (default: false)
351
397
  ```
352
398
 
353
- `AMOUNT` だけがドキュメント化されていますが、`factor` や `clamp`, `notify` も自動的に補完され、既定値や型が推論されていることがわかります。コメントとシグネチャの矛盾を早期に検知したい場合は `RUBYCLI_STRICT=ON` で厳格モードを有効化してください。
399
+ `AMOUNT` だけがドキュメント化されていますが、`factor` や `clamp`, `notify` も自動的に補完され、既定値や型が推論されていることがわかります。開発時は `rubycli --check 対象.rb` でコメントとシグネチャの矛盾を検出し、本番実行で `--strict` を付ければ仕様外の入力をその場で弾けます。
354
400
 
355
401
  #### 存在しない引数やオプションをコメントに書いた場合
356
402
 
@@ -387,6 +433,14 @@ YAML 固有の書き方は拒否され、無効な JSON であれば `JSON::Pars
387
433
 
388
434
  `--eval-args`(短縮形 `-e`)を使うと、後続の引数を Ruby コードとして評価した結果を CLI に渡せます。JSON や YAML では表現しづらいオブジェクトを扱いたいときに便利ですが、評価は `Object.new.instance_eval { binding }` 上で行われるため、信頼できる入力に限定してください。コード内では `Rubycli.with_eval_mode(true) { … }` で切り替えられます。
389
435
 
436
+ Ruby 評価はシンボルや配列/ハッシュもそのまま扱えるため、列挙値の組み合わせをオプションへ渡すときにも役立ちます。
437
+
438
+ ```bash
439
+ rubycli -E scripts/report_runner.rb publish \
440
+ --targets '[:marketing, :sales]' \
441
+ --channels '[:email, :slack]'
442
+ ```
443
+
390
444
  Ruby 評価を使いつつ、構文エラーが出たときは元の文字列にフォールバックさせたい場合は `--eval-lax`(短縮形 `-E`)を指定します。`--eval-args` と同じく eval モードを有効にしますが、Ruby として解釈できなかったトークン(例: 素の `https://example.com`)は警告を出した上でそのまま渡すため、`60*60*24*14` のような式と文字列を気軽に混在させられます。
391
445
 
392
446
  `--json-args`/`-j` は `--eval-args`/`-e` および `--eval-lax`/`-E` と同時指定できません。どのモードも既定のリテラル解析を拡張する位置づけなので、用途に応じて厳格な JSON か Ruby eval(通常/lax)のいずれかを選択してください。
@@ -427,8 +481,9 @@ rubycli --pre-script scripts/bootstrap_runner.rb \
427
481
 
428
482
  | 変数 / フラグ | 説明 | 既定値 |
429
483
  | ------------- | ---- | ------ |
430
- | `--debug` / `RUBYCLI_DEBUG=true` | デバッグログ表示 | `false` |
431
- | `RUBYCLI_STRICT=ON` | 厳格モードを有効化(コメントとシグネチャの矛盾を警告) | `OFF` |
484
+ | `RUBYCLI_DEBUG=true` | デバッグログ表示 | `false` |
485
+ | `--check` | コメント/実装のズレを検査し、コマンドは実行しない | `off` |
486
+ | `--strict` | ドキュメントで許可した型・値以外をエラーとして拒否 | `off` |
432
487
  | `RUBYCLI_ALLOW_PARAM_COMMENT=OFF` | レガシーな `@param` 記法を無効化(互換性のため既定では ON) | `ON` |
433
488
 
434
489
  ## Rubycli API
data/README.md CHANGED
@@ -35,7 +35,6 @@ Available commands:
35
35
  greet <NAME>
36
36
 
37
37
  Detailed command help: hello_app.rb COMMAND help
38
- Enable debug logging: --debug or RUBYCLI_DEBUG=true
39
38
  ```
40
39
 
41
40
  ```bash
@@ -109,7 +108,6 @@ Available commands:
109
108
  greet <NAME> [--shout]
110
109
 
111
110
  Detailed command help: hello_app_with_docs.rb COMMAND help
112
- Enable debug logging: --debug or RUBYCLI_DEBUG=true
113
111
  ```
114
112
 
115
113
  ```bash
@@ -165,13 +163,13 @@ Rubycli assumes that the file name (CamelCased) matches the class or module you
165
163
 
166
164
  This keeps large projects safe by default but still provides a one-flag escape hatch when you prefer the fully automatic behaviour.
167
165
 
168
- > **Instance-only classes** – If a class only defines public *instance* methods (for example, it exposes functionality via `attr_reader` or `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`.
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.
169
167
 
170
168
  ## Project Philosophy
171
169
 
172
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.
173
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.”
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. Enable strict mode (`RUBYCLI_STRICT=ON`) when you want warnings about mismatches.
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.
175
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.
176
174
 
177
175
  ## Features
@@ -180,13 +178,15 @@ This keeps large projects safe by default but still provides a one-flag escape h
180
178
  - Automatic option signature inference (`NAME [Type] Description…`) without extra DSLs
181
179
  - Safe literal parsing out of the box (arrays / hashes / booleans) with opt-in strict JSON and Ruby eval modes
182
180
  - Optional pre-script hook (`--pre-script` / `--init`) to evaluate Ruby and expose the resulting object
183
- - Opt-in strict mode (`RUBYCLI_STRICT=ON`) that emits warnings whenever comments contradict method signatures
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
184
 
185
185
  ## How it differs from Python Fire
186
186
 
187
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
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** – Opt-in strict mode surfaces warnings when comments fall out of sync with method signatures, helping teams keep help text accurate.
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
190
  - **Ruby-centric tooling** – Supports Ruby-specific conventions such as optional keyword arguments, block documentation (`@yield*` tags), and `RUBYCLI_*` environment toggles.
191
191
 
192
192
  | Capability | Python Fire | Rubycli |
@@ -293,15 +293,62 @@ The CLI treats `--flag VALUE`, `--flag <value>`, and `--flag=<value>` identicall
293
293
 
294
294
  > Tip: You do not need to wrap optional arguments in brackets inside the comment. Rubycli already knows which parameters are optional from the Ruby signature and will introduce the brackets in generated help.
295
295
 
296
- You can annotate types using `[String]`, `(String)`, or `(type: String)`—they all convey the same hint, and you can list multiple types such as `(String, nil)` or `(type: String, nil)`.
296
+ You can annotate types using `[String]` or `(String)`—they both convey the same hint, and you can list multiple types such as `(String, nil)`.
297
+
298
+ Repeated values (`VALUE...`) now materialize as arrays automatically whenever the option is documented with an ellipsis (for example `TAG...`) or an explicit array type hint (`[String[]]`, `Array<String>`). Supply either JSON/YAML list syntax (`--tags "[\"build\",\"test\"]"`) or a comma-delimited string (`--tags "build,test"`); Rubycli will coerce both forms to arrays. Space-separated multi-value flags (`--tags build test`) are still not supported, and options without a repeated/array hint continue to be parsed as scalars. Strict mode still verifies each element against the documented type, so `--tags [1,2]` will fail when the docs say `[String[]]`.
297
299
 
298
- Repeated values (`VALUE...`) now materialize as arrays automatically whenever the option is documented with an ellipsis (for example `TAG...`) or an explicit array type hint (`[String[]]`, `Array<String>`). Supply either JSON/YAML list syntax (`--tags "[\"build\",\"test\"]"`) or a comma-delimited string (`--tags "build,test"`); Rubycli will coerce both forms to arrays. Space-separated multi-value flags (`--tags build test`) are still not supported, and options without a repeated/array hint continue to be parsed as scalars.
300
+ Need to pass structures that are awkward to express as JSON (for example symbol arrays or hashes)? Enable eval mode (`--eval-args`/`-e` or `--eval-lax`/`-E`) and supply a Ruby literal that matches the documented type; the example in the eval section below shows how to pass multiple enum selections safely even though space-separated syntax remains unsupported.
299
301
 
300
302
  Common inference rules:
301
303
 
302
304
  - Writing a placeholder such as `ARG1` (without `[String]`) makes Rubycli treat it as a `String`.
303
305
  - Using that placeholder in an option line (`--name ARG1`) also infers a `String`.
304
306
  - Omitting the placeholder entirely (`--verbose`) produces a Boolean flag.
307
+ - Positional arguments only become booleans when you annotate `[Boolean]`; a bare `NAME Description` (or `@param name Description`) falls back to `String`, regardless of the Ruby default value.
308
+
309
+ ### Literal choices and enums
310
+
311
+ You can express a finite set of accepted values directly inside the type annotation, for example `--format MODE [:json, :yaml, :auto]` or `LEVEL [:info, :warn]`. Symbols, strings (including barewords), booleans, numbers, and `nil` are supported, and you can mix literal entries with broader types such as `--channel TARGET [:stdout, :stderr, Boolean]`. `%i[info warn]` / `%w[debug info]` short-hands expand as expected, so `LEVEL %i[info warn]` works the same as the explicit array form. Rubycli always records these choices in the generated help; when you run with `--strict`, any value outside the documented set results in `Rubycli::ArgumentError`, otherwise a warning is printed and execution proceeds.
312
+
313
+ > Symbols and strings are compared strictly. `[:info, :warn]` requires symbol inputs such as `:info`, while `["info", "warn"]` only accepts plain strings. Prefix a value with `:` at the CLI to pass a symbol.
314
+
315
+ > Literal enums currently apply to each scalar argument. If an option is documented as an array (for example `[Symbol[]]`), spell out the allowed members in prose for now—combined literal arrays such as `[%i[foo bar][]]` are not supported.
316
+
317
+ ```bash
318
+ # literal choices + booleans (see examples/strict_choices_demo.rb)
319
+ ruby examples/strict_choices_demo.rb report warn --format json
320
+ #=> [WARN] format=json
321
+
322
+ # the same command with --strict will abort when values drift
323
+ ruby -Ilib exe/rubycli --strict examples/strict_choices_demo.rb report debug
324
+ #=> Rubycli::ArgumentError: Value "debug" for LEVEL is not allowed: allowed values are :info, :warn, :error
325
+ ```
326
+
327
+ ```bash
328
+ # symbol values stay distinct
329
+ ruby -Ilib exe/rubycli --strict examples/strict_choices_demo.rb report :warn
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
334
+ ```
335
+
336
+ ### Standard library type hints
337
+
338
+ Doc comments can reference standard classes such as `Date`, `Time`, `BigDecimal`, or `Pathname`. Rubycli loads the necessary stdlib files on demand and coerces CLI inputs using the documented types.
339
+
340
+ ```bash
341
+ # see examples/typed_arguments_demo.rb
342
+ ruby examples/typed_arguments_demo.rb ingest \
343
+ --date 2024-12-25 \
344
+ --moment 2024-12-25T10:00:00Z \
345
+ --budget 123.45 \
346
+ --input ./data/input.csv
347
+ ```
348
+
349
+ This command prints a normalized summary and the handler receives real `Date`, `Time`, `BigDecimal`, and `Pathname` objects without manual parsing.
350
+
351
+ Each option has a sensible default, so you can also experiment one at a time (for example `ruby examples/typed_arguments_demo.rb ingest --budget 999.99`).
305
352
 
306
353
  Other YARD tags such as `@example`, `@raise`, `@see`, and `@deprecated` are currently ignored by the CLI renderer.
307
354
 
@@ -340,7 +387,6 @@ Available commands:
340
387
  scale AMOUNT [<FACTOR>] [--clamp=<value>] [--notify]
341
388
 
342
389
  Detailed command help: fallback_example.rb COMMAND help
343
- Enable debug logging: --debug or RUBYCLI_DEBUG=true
344
390
  ```
345
391
 
346
392
  ```bash
@@ -359,7 +405,7 @@ Options:
359
405
  --notify [Boolean] optional (default: false)
360
406
  ```
361
407
 
362
- Here only `AMOUNT` is documented, yet `factor`, `clamp`, and `notify` are still presented with sensible defaults and inferred types. Enable strict mode (`RUBYCLI_STRICT=ON`) if you want mismatches between comments and signatures to surface as warnings during development.
408
+ Here only `AMOUNT` is documented, yet `factor`, `clamp`, and `notify` are still presented with sensible defaults and inferred types. Run `rubycli --check path/to/script.rb` during development to surface mismatches between comments and signatures, and pass `--strict` when executing commands to enforce the documented types/choices.
363
409
 
364
410
  #### What if the docs mention arguments that do not exist?
365
411
 
@@ -395,6 +441,14 @@ rubycli -e scripts/data_cli.rb DataCLI run '(1..10).to_a'
395
441
 
396
442
  Under the hood Rubycli evaluates each argument inside an isolated binding (`Object.new.instance_eval { binding }`). Treat this as unsafe input: do not enable it for untrusted callers. The mode can also be toggled programmatically via `Rubycli.with_eval_mode(true) { … }`.
397
443
 
444
+ Because Ruby evaluation understands symbols, arrays, and hashes, it’s a convenient way to pass literal enum combinations to options that expect arrays:
445
+
446
+ ```bash
447
+ rubycli -E scripts/report_runner.rb publish \
448
+ --targets '[:marketing, :sales]' \
449
+ --channels '[:email, :slack]'
450
+ ```
451
+
398
452
  Need Ruby evaluation plus a safety net? Pass `--eval-lax` (or `-E`). It flips on eval mode just like `--eval-args`, but if Ruby fails to parse a token (for example, a bare `https://example.com`), Rubycli emits a warning and forwards the original string unchanged. This lets you mix inline math (`60*60*24*14`) with literal values without constantly juggling quotes.
399
453
 
400
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.
@@ -435,8 +489,9 @@ This keeps `--new` available for quick zero-argument instantiation while allowin
435
489
 
436
490
  | Flag / Env | Description | Default |
437
491
  | ---------- | ----------- | ------- |
438
- | `--debug` / `RUBYCLI_DEBUG=true` | Print debug logs | `false` |
439
- | `RUBYCLI_STRICT=ON` | Enable strict mode validation (prints warnings on comment/signature drift) | `OFF` |
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` |
440
495
  | `RUBYCLI_ALLOW_PARAM_COMMENT=OFF` | Disable legacy `@param` lines (defaults to on today for compatibility) | `ON` |
441
496
 
442
497
  ## Library helpers