rubycli 0.1.1 → 0.1.4
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 +42 -1
- data/README.ja.md +80 -43
- data/README.md +92 -42
- data/lib/rubycli/argument_mode_controller.rb +69 -0
- data/lib/rubycli/argument_parser.rb +71 -80
- data/lib/rubycli/arguments/token_stream.rb +41 -0
- data/lib/rubycli/arguments/value_converter.rb +74 -0
- data/lib/rubycli/cli.rb +9 -6
- data/lib/rubycli/command_line.rb +29 -11
- data/lib/rubycli/constant_capture.rb +50 -0
- data/lib/rubycli/documentation/comment_extractor.rb +52 -0
- data/lib/rubycli/documentation/metadata_parser.rb +838 -0
- data/lib/rubycli/documentation_registry.rb +10 -797
- data/lib/rubycli/environment.rb +8 -1
- data/lib/rubycli/eval_coercer.rb +16 -1
- data/lib/rubycli/help_renderer.rb +162 -116
- data/lib/rubycli/type_utils.rb +28 -1
- data/lib/rubycli/version.rb +1 -1
- data/lib/rubycli.rb +196 -118
- metadata +9 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a71a438637363ea54e22377b645dc99a26a0c91692571bf57a68368403e32308
|
|
4
|
+
data.tar.gz: 367b354b2ffde5ee80e7ee3ee5b2858f15cbf8097cc8346fd812b780f41443e2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5eb055a5cbaa3daf0d311b67922a0c9bb7dbb8a75c2844524dc21f5faed232f560c8f1aaea6caf96737fea0b979625813b1ea5cc6c589ecee405b994b07ee16f
|
|
7
|
+
data.tar.gz: f64107c28083a96674970f8414090e47b77a749f8d3c9393ff9ca972a747ebe36a5da128d1c75a313ca570631436509392985477d1eefe271722eb4b046c69a8
|
data/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,47 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## [0.1.
|
|
3
|
+
## [0.1.4] - 2025-11-08
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
- Re-cut the release that was briefly published as 0.1.3 (and yanked) so RubyGems now hosts the complete set of changes listed below.
|
|
7
|
+
|
|
8
|
+
> _Note:_ 0.1.3 was yanked before general availability; consumers should upgrade directly to 0.1.4.
|
|
9
|
+
|
|
10
|
+
## [0.1.3] - 2025-11-08
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- TracePoint-backed constant capture so Rubycli can detect CLI classes/modules even when they are defined indirectly; bundled example and tests illustrate the behavior.
|
|
14
|
+
- Strict/auto constant selection modes with the new `--auto-target` / `-a` flag so single callable constants are picked automatically when requested.
|
|
15
|
+
- `--eval-lax` / `-E` argument mode that evaluates Ruby inputs but gracefully falls back to raw strings on parse failures.
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
- Argument parsing internals were modularized so JSON/eval coercion now flows through a dedicated controller, simplifying future extensions.
|
|
19
|
+
- `rubycli` now returns explicit status codes for success and failure, improving scriptability.
|
|
20
|
+
- CLI constant selection errors provide clearer guidance, document the `--new` behavior, and consistently refer to the `--auto-target` flag.
|
|
21
|
+
|
|
22
|
+
### Documentation
|
|
23
|
+
- Clarified the authoritative source for documentation comments, reorganized helper logic in the showcase example, and expanded guidance around constant modes.
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
- CLI no longer dumps a Ruby backtrace when `Rubycli::Runner` reports user-facing errors; only the curated guidance is shown.
|
|
27
|
+
|
|
28
|
+
## [0.1.2] - 2025-11-06
|
|
29
|
+
|
|
30
|
+
### Added
|
|
31
|
+
- Example `examples/documentation_style_showcase.rb` covering all supported documentation notations.
|
|
32
|
+
- Parenthesised `(Type)` and `(type: Type)` annotations for positional and option documentation.
|
|
33
|
+
|
|
34
|
+
### Documentation
|
|
35
|
+
- Linked the showcase example from the English and Japanese READMEs to highlight the new syntax.
|
|
36
|
+
- Clarified that optional arguments do not require brackets in comments and noted the current comma-delimited behaviour for repeated values.
|
|
37
|
+
- Documented the refined literal parsing guard rails so only structured values auto-coerce while plain strings stay untouched unless type hints request otherwise.
|
|
38
|
+
|
|
39
|
+
### Fixed
|
|
40
|
+
- Restored uppercase positional placeholders in the generated help output so the default style stays consistent.
|
|
41
|
+
- Help renderer now preserves documented placeholder casing instead of wrapping everything in `<...>`.
|
|
42
|
+
- Default literal parsing now skips generic strings to avoid collapsing comma-separated inputs, while still supporting array coercion when documentation specifies list types.
|
|
43
|
+
|
|
44
|
+
## [0.1.1] - 2025-11-01
|
|
4
45
|
|
|
5
46
|
### Added
|
|
6
47
|
- Initial public release of Rubycli with the `rubycli` executable for running documented Ruby classes and modules.
|
data/README.ja.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# Rubycli — Python Fire 風の Ruby 向け CLI
|
|
2
2
|
|
|
3
|
-
Rubycli
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
Rubycli は Ruby のクラス/モジュールにある公開メソッドの定義と、そのメソッドに付けたドキュメントコメントから CLI を自動生成する小さなフレームワークです。Python Fire にインスパイアされていますが、互換や公式ポートを目指すものではありません。Ruby のコメント記法と型アノテーションに合わせて設計しており、コメントに書いた型ヒントや繰り返し指定が CLI の引数解釈もコントロールします。
|
|
4
6
|
|
|
5
7
|
> English guide is available in [README.md](README.md).
|
|
6
8
|
|
|
@@ -28,7 +30,7 @@ Usage: hello_app.rb COMMAND [arguments]
|
|
|
28
30
|
|
|
29
31
|
Available commands:
|
|
30
32
|
Class methods:
|
|
31
|
-
greet <
|
|
33
|
+
greet <NAME>
|
|
32
34
|
|
|
33
35
|
Detailed command help: hello_app.rb COMMAND help
|
|
34
36
|
Enable debug logging: --debug or RUBYCLI_DEBUG=true
|
|
@@ -40,10 +42,10 @@ rubycli examples/hello_app.rb greet
|
|
|
40
42
|
|
|
41
43
|
```text
|
|
42
44
|
Error: wrong number of arguments (given 0, expected 1)
|
|
43
|
-
Usage: hello_app.rb greet
|
|
45
|
+
Usage: hello_app.rb greet NAME
|
|
44
46
|
|
|
45
47
|
Positional arguments:
|
|
46
|
-
NAME
|
|
48
|
+
NAME required
|
|
47
49
|
```
|
|
48
50
|
|
|
49
51
|
```bash
|
|
@@ -102,7 +104,7 @@ Usage: hello_app_with_docs.rb COMMAND [arguments]
|
|
|
102
104
|
|
|
103
105
|
Available commands:
|
|
104
106
|
Class methods:
|
|
105
|
-
greet <
|
|
107
|
+
greet <NAME> [--shout]
|
|
106
108
|
|
|
107
109
|
Detailed command help: hello_app_with_docs.rb COMMAND help
|
|
108
110
|
Enable debug logging: --debug or RUBYCLI_DEBUG=true
|
|
@@ -113,13 +115,13 @@ rubycli examples/hello_app_with_docs.rb greet --help
|
|
|
113
115
|
```
|
|
114
116
|
|
|
115
117
|
```text
|
|
116
|
-
Usage: hello_app_with_docs.rb greet
|
|
118
|
+
Usage: hello_app_with_docs.rb greet NAME [--shout]
|
|
117
119
|
|
|
118
120
|
Positional arguments:
|
|
119
|
-
NAME [String]
|
|
121
|
+
NAME [String] required 挨拶対象
|
|
120
122
|
|
|
121
123
|
Options:
|
|
122
|
-
--shout [Boolean]
|
|
124
|
+
--shout [Boolean] optional 大文字で出力 (default: false)
|
|
123
125
|
```
|
|
124
126
|
|
|
125
127
|
```bash
|
|
@@ -145,18 +147,31 @@ end
|
|
|
145
147
|
|
|
146
148
|
`ruby hello_app.rb ...` の形で呼び出したい場合だけ `require "rubycli"` を追加し、`Rubycli.run` に制御を渡します(後述のクイックスタート参照)。
|
|
147
149
|
|
|
150
|
+
## 定数解決モード
|
|
151
|
+
|
|
152
|
+
Rubycli は「ファイル名を CamelCase にした定数」を公開対象だと想定しています。ファイル名とクラス/モジュール名が一致しない場合は、次のモードで挙動を切り替えられます。
|
|
153
|
+
|
|
154
|
+
| モード | 有効化方法 | 挙動 |
|
|
155
|
+
| --- | --- | --- |
|
|
156
|
+
| `strict`(デフォルト) | 何もしない / `RUBYCLI_AUTO_TARGET=strict` | CamelCase が一致しないとエラーになります。検出した定数一覧と再実行コマンド例を表示します。 |
|
|
157
|
+
| `auto` | `--auto-target`(短縮 `-a`) または `RUBYCLI_AUTO_TARGET=auto` | ファイル内で CLI として実行できる定数が 1 つだけなら自動選択します。複数あれば従来通りエラーで案内します。 |
|
|
158
|
+
|
|
159
|
+
大規模なコードベースでも安全側を保ちながら、どうしても自動選択したいときだけ 1 フラグで切り替えられます。
|
|
160
|
+
|
|
161
|
+
> **インスタンスメソッド専用のクラスについて** – 公開メソッドがインスタンス側(`attr_reader` や `def greet`)にしか無い場合は、`--new` を付けて事前にインスタンス化しないと CLI から呼び出せません。クラスメソッドを 1 つ用意するか、`--new` を明示して実行してください。
|
|
162
|
+
|
|
148
163
|
## 開発方針
|
|
149
164
|
|
|
150
165
|
- **便利さが最優先** – 既存の Ruby スクリプトを最小の手間で CLI 化できることを目的にしており、Python Fire の完全移植は目指していません。
|
|
151
166
|
- **インスパイアであってポートではない** – アイデアの出自は Fire ですが、同等機能を揃える予定は基本的にありません。Fire 由来の未実装機能は仕様です。
|
|
152
|
-
-
|
|
167
|
+
- **メソッド定義が土台、コメントが挙動を補強** – 公開メソッドのシグネチャが CLI に露出する範囲と必須/任意を決めますが、コメントに `TAG...` や `[Integer]` を書くと同じ引数でも配列化や型変換が行われます。コメントと実装のズレを観測したいときだけ `RUBYCLI_STRICT=ON` で厳格モードを有効化し、警告を受け取ります。
|
|
153
168
|
- **軽量メンテナンス** – 実装の多くは AI 支援で作られており、深い Ruby メタプログラミングを伴う大規模拡張は想定外です。Fire 互換を求める PR は事前相談をお願いします。
|
|
154
169
|
|
|
155
170
|
## 特徴
|
|
156
171
|
|
|
157
172
|
- コメントベースで CLI オプションやヘルプを自動生成
|
|
158
173
|
- YARD 形式と `NAME [Type] 説明…` の簡潔記法を同時サポート
|
|
159
|
-
-
|
|
174
|
+
- 引数はデフォルトで安全なリテラルとして解釈し、必要に応じて厳格 JSON モードや Ruby eval モードを切り替え可能
|
|
160
175
|
- `--pre-script`(エイリアス: `--init`)で任意の Ruby コードを評価し、その結果オブジェクトを公開
|
|
161
176
|
- `RUBYCLI_STRICT=ON` で有効化できる厳格モードにより、コメントとシグネチャの矛盾を警告として検知可能
|
|
162
177
|
|
|
@@ -170,28 +185,24 @@ end
|
|
|
170
185
|
| 機能 | Python Fire | Rubycli |
|
|
171
186
|
| ---- | ----------- | -------- |
|
|
172
187
|
| 属性の辿り方 | オブジェクトを辿ってプロパティ/属性を自動公開 | 対象オブジェクトの公開メソッドをそのまま公開(暗黙の辿りは無し) |
|
|
173
|
-
| クラス初期化 | `__init__` 引数を CLI で自動受け取りインスタンス化 | `--new`
|
|
188
|
+
| クラス初期化 | `__init__` 引数を CLI で自動受け取りインスタンス化 | `--new` 指定時だけ引数なしで明示的に初期化(初期化引数の CLI 受け渡しは未対応なので、必要なら pre-script や自前ファクトリで注入) |
|
|
174
189
|
| インタラクティブシェル | コマンド未指定時に Fire REPL を提供 | インタラクティブモード無し。コマンド実行専用 |
|
|
175
190
|
| 情報源 | 反射で引数・プロパティを解析 | ライブなメソッド定義を基点にしつつコメントをヘルプへ反映 |
|
|
176
191
|
| 辞書/配列 | dict/list を自動でサブコマンド化 | クラス/モジュールのメソッドに特化(辞書自動展開なし) |
|
|
177
192
|
|
|
178
193
|
## インストール
|
|
179
194
|
|
|
180
|
-
|
|
195
|
+
Rubycli は RubyGems からインストールできます。
|
|
181
196
|
|
|
182
197
|
```bash
|
|
183
|
-
|
|
184
|
-
cd rubycli
|
|
185
|
-
# gem build rubycli.gemspec
|
|
186
|
-
gem build rubycli.gemspec
|
|
187
|
-
gem install rubycli-<version>.gem
|
|
198
|
+
gem install rubycli
|
|
188
199
|
```
|
|
189
200
|
|
|
190
201
|
Bundler 例:
|
|
191
202
|
|
|
192
203
|
```ruby
|
|
193
204
|
# Gemfile
|
|
194
|
-
gem "rubycli"
|
|
205
|
+
gem "rubycli"
|
|
195
206
|
```
|
|
196
207
|
|
|
197
208
|
## クイックスタート(Rubycli をスクリプトに組み込む)
|
|
@@ -247,22 +258,46 @@ rubycli scripts/multi_runner.rb Admin::Runner list --active
|
|
|
247
258
|
|
|
248
259
|
## コメント記法
|
|
249
260
|
|
|
250
|
-
| 用途 | YARD 互換 |
|
|
251
|
-
| ---- | --------- |
|
|
252
|
-
| 位置引数 | `@param name [Type] 説明` | `NAME [Type]
|
|
253
|
-
| キーワード引数 | 同上 | `--flag -f
|
|
261
|
+
| 用途 | YARD 互換 | Rubycli 標準 |
|
|
262
|
+
| ---- | --------- | ----------- |
|
|
263
|
+
| 位置引数 | `@param name [Type] 説明` | `NAME [Type] 説明` |
|
|
264
|
+
| キーワード引数 | 同上 | `--flag -f VALUE [Type] 説明` |
|
|
254
265
|
| 戻り値 | `@return [Type] 説明` | `=> [Type] 説明` |
|
|
255
266
|
|
|
256
|
-
|
|
267
|
+
短いオプション(`-f` など)は任意で、登場順も自由です。Rubycli 標準の書き方では次の例が同義になります。
|
|
268
|
+
|
|
269
|
+
- `--flag -f VALUE [Type] 説明`
|
|
270
|
+
- `--flag VALUE [Type] 説明`
|
|
271
|
+
- `-f --flag VALUE [Type] 説明`
|
|
272
|
+
|
|
273
|
+
README のサンプルは既定スタイルとして大文字プレースホルダ(`NAME`, `VALUE` など)を使用しています。次項以降の表記揺れは、必要に応じて選べる追加記法です。
|
|
274
|
+
|
|
275
|
+
### 互換プレースホルダ表記
|
|
276
|
+
|
|
277
|
+
コメントやヘルプ出力では次の表記も同じ意味として解釈されます。
|
|
278
|
+
|
|
279
|
+
- 山括弧で値を明示: `--flag <value>`, `NAME [<value>]`
|
|
280
|
+
- ロングオプションの `=` 付き表記: `--flag=<value>`
|
|
281
|
+
- 繰り返し指定: `VALUE...`, `<value>...`
|
|
282
|
+
|
|
283
|
+
実行時には `--flag VALUE`, `--flag <value>`, `--flag=<value>` のどれで入力しても同じ扱いです。プロジェクトで読みやすいスタイルを選択してください。`[VALUE]` や `[VALUE...]` のような表記を使うと、真偽値・任意値・リストなどの推論が働きます。値プレースホルダを省略したオプション(例: `--quiet`)は自動で Boolean フラグとして扱われます。
|
|
284
|
+
|
|
285
|
+
> 補足: コメント内で任意引数を角括弧で表す必要はありません。Ruby 側のメソッドシグネチャから必須/任意は自動判定され、ヘルプ出力では Rubycli が適切に角括弧を追加します。
|
|
286
|
+
|
|
287
|
+
型ヒントは `[String]`, `(String)`, `(type: String)` のように角括弧・丸括弧・`type:` プレフィックスのいずれでも指定できます。複数型は `(String, nil)` や `(type: String, nil)` のように列挙してください。
|
|
288
|
+
|
|
289
|
+
`VALUE...` のような繰り返し指定(`TAG...` など)や、`[String[]]` / `Array<String>` といった配列型の注釈が付いたオプションは配列として扱われます。JSON/YAML 形式のリスト(例: `--tags '["build","test"]'`)を渡すか、カンマ区切り文字列(`--tags "build,test"`)を渡すことで配列に変換されます。スペース区切りの複数値入力(`--tags build test`)にはまだ対応しておらず、繰り返し注記のないオプションは従来どおりスカラーとして扱われます。
|
|
257
290
|
|
|
258
291
|
代表的な推論例:
|
|
259
292
|
|
|
260
|
-
- `ARG1`
|
|
261
|
-
- `--name ARG1`
|
|
293
|
+
- `ARG1` のように型ラベルを省略したプレースホルダは既定で `String` として扱われます。
|
|
294
|
+
- `--name ARG1` のようにオプションへプレースホルダだけを指定しても同じく `String` が推論されます。
|
|
262
295
|
- `--verbose` のように値プレースホルダを省略したオプションは Boolean フラグとして扱われます。
|
|
263
296
|
|
|
264
297
|
`@example` や `@raise`, `@see`, `@deprecated` などその他の YARD タグは、現状ヘルプ出力には反映されません。
|
|
265
298
|
|
|
299
|
+
> すべての記法をまとめて試したい場合は `rubycli examples/documentation_style_showcase.rb canonical --help` や `... angled --help` などを実行してみてください。
|
|
300
|
+
|
|
266
301
|
従来の `@param` 記法も既定で利用できます。簡潔なプレースホルダ記法だけに限定したい場合は `RUBYCLI_ALLOW_PARAM_COMMENT=OFF` を設定してください(厳格モードでの検証は継続されます)。
|
|
267
302
|
|
|
268
303
|
### コメントが不足している場合のフォールバック
|
|
@@ -293,7 +328,7 @@ Usage: fallback_example.rb COMMAND [arguments]
|
|
|
293
328
|
|
|
294
329
|
Available commands:
|
|
295
330
|
Class methods:
|
|
296
|
-
scale
|
|
331
|
+
scale AMOUNT [<FACTOR>] [--clamp=<value>] [--notify]
|
|
297
332
|
|
|
298
333
|
Detailed command help: fallback_example.rb COMMAND help
|
|
299
334
|
Enable debug logging: --debug or RUBYCLI_DEBUG=true
|
|
@@ -304,15 +339,15 @@ rubycli examples/fallback_example.rb scale --help
|
|
|
304
339
|
```
|
|
305
340
|
|
|
306
341
|
```text
|
|
307
|
-
Usage: fallback_example.rb scale
|
|
342
|
+
Usage: fallback_example.rb scale AMOUNT [FACTOR] [--clamp=<CLAMP>] [--notify]
|
|
308
343
|
|
|
309
344
|
Positional arguments:
|
|
310
|
-
AMOUNT
|
|
311
|
-
|
|
345
|
+
AMOUNT [Integer] required 処理対象の数値
|
|
346
|
+
FACTOR optional (default: 2)
|
|
312
347
|
|
|
313
348
|
Options:
|
|
314
|
-
--clamp
|
|
315
|
-
--notify
|
|
349
|
+
--clamp=<CLAMP> [String] optional (default: nil)
|
|
350
|
+
--notify [Boolean] optional (default: false)
|
|
316
351
|
```
|
|
317
352
|
|
|
318
353
|
`AMOUNT` だけがドキュメント化されていますが、`factor` や `clamp`, `notify` も自動的に補完され、既定値や型が推論されていることがわかります。コメントとシグネチャの矛盾を早期に検知したい場合は `RUBYCLI_STRICT=ON` で厳格モードを有効化してください。
|
|
@@ -332,27 +367,29 @@ Options:
|
|
|
332
367
|
- `@param` の行に続く箇条書きや補足行は CLI の自動生成には使われません。補足情報を表示したい場合は、`--flag ...` 行の説明に含めるか、README など別のドキュメントで扱ってください。
|
|
333
368
|
- `RUBYCLI_ALLOW_PARAM_COMMENT=OFF` にすると `@param`/`@return` などのタグは警告扱いになります。プロジェクト内で簡潔記法へ統一するときはこの環境変数で段階的に移行できます。
|
|
334
369
|
|
|
335
|
-
##
|
|
370
|
+
## 引数解析モード
|
|
336
371
|
|
|
337
|
-
|
|
372
|
+
### 既定のリテラル解析
|
|
338
373
|
|
|
339
|
-
|
|
340
|
-
rubycli --json-args my_cli.rb MyCLI run '["--config", "{\"foo\":1}"]'
|
|
341
|
-
```
|
|
342
|
-
|
|
343
|
-
プログラム側では `Rubycli.with_json_mode(true) { … }` で同じ効果を得られます。
|
|
374
|
+
Rubycli は `{` や `[`、クォート、YAML の先頭記号といった「構造化リテラルらしい」形の引数に対して `Psych.safe_load` を試み、成功すれば Ruby の配列/ハッシュ/真偽値に変換してからメソッドへ渡します。たとえば `--names='["Alice","Bob"]'` や `--config='{foo: 1}'` のような値は追加フラグ無しでネイティブな配列・ハッシュとして届きます。一方、プレーンな `1,2,3` のような文字列はこの段階ではそのまま維持されます(コメントで `String[]` や `TAG...` と宣言されている場合は後段で配列に整形されます)。扱えない形式は自動的に文字列へフォールバックするため、`"2024-01-01"` のような値もそのまま文字列で受け取れますし、構文が崩れていても CLI 全体が落ちることはありません。
|
|
344
375
|
|
|
345
|
-
|
|
376
|
+
### JSON モード
|
|
346
377
|
|
|
347
|
-
`--
|
|
378
|
+
CLI 実行時に `--json-args`(短縮形 `-j`)を付けると、後続の引数が厳格に JSON として解釈されます。
|
|
348
379
|
|
|
349
380
|
```bash
|
|
350
|
-
rubycli
|
|
381
|
+
rubycli -j my_cli.rb MyCLI run '["--config", "{\"foo\":1}"]'
|
|
351
382
|
```
|
|
352
383
|
|
|
353
|
-
|
|
384
|
+
YAML 固有の書き方は拒否され、無効な JSON であれば `JSON::ParserError` が発生するため、入力の妥当性を強く保証したいときに便利です。プログラム側では `Rubycli.with_json_mode(true) { … }` で有効化できます。
|
|
385
|
+
|
|
386
|
+
### Eval モード
|
|
387
|
+
|
|
388
|
+
`--eval-args`(短縮形 `-e`)を使うと、後続の引数を Ruby コードとして評価した結果を CLI に渡せます。JSON や YAML では表現しづらいオブジェクトを扱いたいときに便利ですが、評価は `Object.new.instance_eval { binding }` 上で行われるため、信頼できる入力に限定してください。コード内では `Rubycli.with_eval_mode(true) { … }` で切り替えられます。
|
|
389
|
+
|
|
390
|
+
Ruby 評価を使いつつ、構文エラーが出たときは元の文字列にフォールバックさせたい場合は `--eval-lax`(短縮形 `-E`)を指定します。`--eval-args` と同じく eval モードを有効にしますが、Ruby として解釈できなかったトークン(例: 素の `https://example.com`)は警告を出した上でそのまま渡すため、`60*60*24*14` のような式と文字列を気軽に混在させられます。
|
|
354
391
|
|
|
355
|
-
`--
|
|
392
|
+
`--json-args`/`-j` は `--eval-args`/`-e` および `--eval-lax`/`-E` と同時指定できません。どのモードも既定のリテラル解析を拡張する位置づけなので、用途に応じて厳格な JSON か Ruby eval(通常/lax)のいずれかを選択してください。
|
|
356
393
|
|
|
357
394
|
## Pre-script ブートストラップ
|
|
358
395
|
|
data/README.md
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
# Rubycli — Python Fire-inspired CLI for Ruby
|
|
2
2
|
|
|
3
|
-
Rubycli
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
Rubycli turns existing Ruby classes and modules into CLIs by inspecting their public method definitions and the doc comments attached to those methods. It is inspired by [Python Fire](https://github.com/google/python-fire) but is not a drop-in port or an official project; the focus here is Ruby’s documentation conventions and type annotations, and those annotations can actively change how a CLI argument is coerced (for example, `TAG... [String[]]` forces array parsing).
|
|
4
6
|
|
|
5
7
|
> 🇯🇵 Japanese documentation is available in [README.ja.md](README.ja.md).
|
|
6
8
|
|
|
9
|
+

|
|
10
|
+
|
|
7
11
|
### 1. Existing Ruby script (Rubycli unaware)
|
|
8
12
|
|
|
9
13
|
```ruby
|
|
@@ -28,7 +32,7 @@ Usage: hello_app.rb COMMAND [arguments]
|
|
|
28
32
|
|
|
29
33
|
Available commands:
|
|
30
34
|
Class methods:
|
|
31
|
-
greet <
|
|
35
|
+
greet <NAME>
|
|
32
36
|
|
|
33
37
|
Detailed command help: hello_app.rb COMMAND help
|
|
34
38
|
Enable debug logging: --debug or RUBYCLI_DEBUG=true
|
|
@@ -40,10 +44,10 @@ rubycli examples/hello_app.rb greet
|
|
|
40
44
|
|
|
41
45
|
```text
|
|
42
46
|
Error: wrong number of arguments (given 0, expected 1)
|
|
43
|
-
Usage: hello_app.rb greet
|
|
47
|
+
Usage: hello_app.rb greet NAME
|
|
44
48
|
|
|
45
49
|
Positional arguments:
|
|
46
|
-
NAME
|
|
50
|
+
NAME required
|
|
47
51
|
```
|
|
48
52
|
|
|
49
53
|
```bash
|
|
@@ -102,7 +106,7 @@ Usage: hello_app_with_docs.rb COMMAND [arguments]
|
|
|
102
106
|
|
|
103
107
|
Available commands:
|
|
104
108
|
Class methods:
|
|
105
|
-
greet <
|
|
109
|
+
greet <NAME> [--shout]
|
|
106
110
|
|
|
107
111
|
Detailed command help: hello_app_with_docs.rb COMMAND help
|
|
108
112
|
Enable debug logging: --debug or RUBYCLI_DEBUG=true
|
|
@@ -113,13 +117,13 @@ rubycli examples/hello_app_with_docs.rb greet --help
|
|
|
113
117
|
```
|
|
114
118
|
|
|
115
119
|
```text
|
|
116
|
-
Usage: hello_app_with_docs.rb greet
|
|
120
|
+
Usage: hello_app_with_docs.rb greet NAME [--shout]
|
|
117
121
|
|
|
118
122
|
Positional arguments:
|
|
119
|
-
NAME [String]
|
|
123
|
+
NAME [String] required Name to greet
|
|
120
124
|
|
|
121
125
|
Options:
|
|
122
|
-
--shout [Boolean]
|
|
126
|
+
--shout [Boolean] optional Print in uppercase (default: false)
|
|
123
127
|
```
|
|
124
128
|
|
|
125
129
|
```bash
|
|
@@ -143,20 +147,38 @@ end
|
|
|
143
147
|
|
|
144
148
|
### 3. (Optional) Embed the runner inside your script
|
|
145
149
|
|
|
146
|
-
Prefer to launch via `ruby
|
|
150
|
+
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`).
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
ruby examples/hello_app_with_require.rb greet Hanako --shout
|
|
154
|
+
#=> HELLO, HANAKO!
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Constant resolution modes
|
|
158
|
+
|
|
159
|
+
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:
|
|
160
|
+
|
|
161
|
+
| Mode | How to enable | Behaviour |
|
|
162
|
+
| --- | --- | --- |
|
|
163
|
+
| `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. |
|
|
164
|
+
| `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. |
|
|
165
|
+
|
|
166
|
+
This keeps large projects safe by default but still provides a one-flag escape hatch when you prefer the fully automatic behaviour.
|
|
167
|
+
|
|
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`.
|
|
147
169
|
|
|
148
170
|
## Project Philosophy
|
|
149
171
|
|
|
150
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.
|
|
151
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.”
|
|
152
|
-
- **
|
|
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.
|
|
153
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.
|
|
154
176
|
|
|
155
177
|
## Features
|
|
156
178
|
|
|
157
179
|
- Comment-aware CLI generation with both YARD-style tags and concise placeholders
|
|
158
180
|
- Automatic option signature inference (`NAME [Type] Description…`) without extra DSLs
|
|
159
|
-
-
|
|
181
|
+
- Safe literal parsing out of the box (arrays / hashes / booleans) with opt-in strict JSON and Ruby eval modes
|
|
160
182
|
- Optional pre-script hook (`--pre-script` / `--init`) to evaluate Ruby and expose the resulting object
|
|
161
183
|
- Opt-in strict mode (`RUBYCLI_STRICT=ON`) that emits warnings whenever comments contradict method signatures
|
|
162
184
|
|
|
@@ -170,36 +192,32 @@ Prefer to launch via `ruby hello_app.rb ...`? Require the gem and delegate to `R
|
|
|
170
192
|
| Capability | Python Fire | Rubycli |
|
|
171
193
|
| ---------- | ----------- | -------- |
|
|
172
194
|
| Attribute traversal | Recursively exposes attributes/properties on demand | Exposes public methods defined on the target; no implicit traversal |
|
|
173
|
-
| Constructor handling | Automatically prompts for `__init__` args when instantiating classes |
|
|
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) |
|
|
174
196
|
| Interactive shell | Offers Fire-specific REPL when invoked without command | No interactive shell mode; strictly command execution |
|
|
175
197
|
| Input discovery | Pure reflection, no doc comments required | Doc comments drive option names, placeholders, and validation |
|
|
176
198
|
| Data structures | Dictionaries / lists become subcommands by default | Focused on class or module methods; no automatic dict/list expansion |
|
|
177
199
|
|
|
178
200
|
## Installation
|
|
179
201
|
|
|
180
|
-
|
|
202
|
+
Rubycli is published on RubyGems.
|
|
181
203
|
|
|
182
204
|
```bash
|
|
183
|
-
|
|
184
|
-
cd rubycli
|
|
185
|
-
# gem build rubycli.gemspec
|
|
186
|
-
gem build rubycli.gemspec
|
|
187
|
-
gem install rubycli-<version>.gem
|
|
205
|
+
gem install rubycli
|
|
188
206
|
```
|
|
189
207
|
|
|
190
208
|
Bundler example:
|
|
191
209
|
|
|
192
210
|
```ruby
|
|
193
211
|
# Gemfile
|
|
194
|
-
gem "rubycli"
|
|
212
|
+
gem "rubycli"
|
|
195
213
|
```
|
|
196
214
|
|
|
197
215
|
## Quick start (embed Rubycli in the script)
|
|
198
216
|
|
|
199
|
-
Step 3 adds `require "rubycli"` so the script can invoke the CLI directly:
|
|
217
|
+
Step 3 adds `require "rubycli"` so the script can invoke the CLI directly (see `examples/hello_app_with_require.rb`):
|
|
200
218
|
|
|
201
219
|
```ruby
|
|
202
|
-
#
|
|
220
|
+
# hello_app_with_require.rb
|
|
203
221
|
require "rubycli"
|
|
204
222
|
|
|
205
223
|
module HelloApp
|
|
@@ -222,10 +240,10 @@ Rubycli.run(HelloApp)
|
|
|
222
240
|
Run it:
|
|
223
241
|
|
|
224
242
|
```bash
|
|
225
|
-
ruby
|
|
243
|
+
ruby examples/hello_app_with_require.rb greet Taro
|
|
226
244
|
#=> Hello, Taro!
|
|
227
245
|
|
|
228
|
-
ruby
|
|
246
|
+
ruby examples/hello_app_with_require.rb greet Taro --shout
|
|
229
247
|
#=> HELLO, TARO!
|
|
230
248
|
```
|
|
231
249
|
|
|
@@ -249,22 +267,46 @@ This is useful when a file defines multiple candidates or when you want a nested
|
|
|
249
267
|
|
|
250
268
|
Rubycli parses a hybrid format – you can stick to familiar YARD tags or use short forms.
|
|
251
269
|
|
|
252
|
-
| Purpose | YARD-compatible |
|
|
253
|
-
| ------- | --------------- |
|
|
254
|
-
| Positional argument | `@param name [Type] Description` | `NAME [Type] Description`
|
|
255
|
-
| Keyword option | Same as above | `--flag -f
|
|
270
|
+
| Purpose | YARD-compatible | Rubycli style |
|
|
271
|
+
| ------- | --------------- | ------------- |
|
|
272
|
+
| Positional argument | `@param name [Type] Description` | `NAME [Type] Description` |
|
|
273
|
+
| Keyword option | Same as above | `--flag -f VALUE [Type] Description` |
|
|
256
274
|
| Return value | `@return [Type] Description` | `=> [Type] Description` |
|
|
257
275
|
|
|
258
|
-
|
|
276
|
+
Short options are optional and order-independent, so the following examples are equivalent in Rubycli’s default style:
|
|
277
|
+
|
|
278
|
+
- `--flag -f VALUE [Type] Description`
|
|
279
|
+
- `--flag VALUE [Type] Description`
|
|
280
|
+
- `-f --flag VALUE [Type] Description`
|
|
281
|
+
|
|
282
|
+
Our examples keep the classic uppercase placeholders (`NAME`, `VALUE`) as the canonical style; the variations below are optional sugar.
|
|
283
|
+
|
|
284
|
+
### Alternate placeholder notations
|
|
285
|
+
|
|
286
|
+
Rubycli also understands these syntaxes when parsing comments and rendering help:
|
|
287
|
+
|
|
288
|
+
- Angle brackets for user input: `--flag <value>` or `NAME [<value>]`
|
|
289
|
+
- Inline equals for long options: `--flag=<value>`
|
|
290
|
+
- Trailing ellipsis for repeated values: `VALUE...` or `<value>...`
|
|
291
|
+
|
|
292
|
+
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.
|
|
293
|
+
|
|
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
|
+
|
|
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)`.
|
|
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.
|
|
259
299
|
|
|
260
300
|
Common inference rules:
|
|
261
301
|
|
|
262
|
-
- Writing a
|
|
302
|
+
- Writing a placeholder such as `ARG1` (without `[String]`) makes Rubycli treat it as a `String`.
|
|
263
303
|
- Using that placeholder in an option line (`--name ARG1`) also infers a `String`.
|
|
264
304
|
- Omitting the placeholder entirely (`--verbose`) produces a Boolean flag.
|
|
265
305
|
|
|
266
306
|
Other YARD tags such as `@example`, `@raise`, `@see`, and `@deprecated` are currently ignored by the CLI renderer.
|
|
267
307
|
|
|
308
|
+
> Want to explore every notation in a single script? Try `rubycli examples/documentation_style_showcase.rb canonical --help`, `... angled --help`, or the other showcase commands.
|
|
309
|
+
|
|
268
310
|
YARD-style `@param` annotations continue to work out of the box. If you want to enforce the concise placeholder syntax exclusively, set `RUBYCLI_ALLOW_PARAM_COMMENT=OFF` (strict mode still applies either way).
|
|
269
311
|
|
|
270
312
|
### When docs are missing or incomplete
|
|
@@ -295,7 +337,7 @@ Usage: fallback_example.rb COMMAND [arguments]
|
|
|
295
337
|
|
|
296
338
|
Available commands:
|
|
297
339
|
Class methods:
|
|
298
|
-
scale
|
|
340
|
+
scale AMOUNT [<FACTOR>] [--clamp=<value>] [--notify]
|
|
299
341
|
|
|
300
342
|
Detailed command help: fallback_example.rb COMMAND help
|
|
301
343
|
Enable debug logging: --debug or RUBYCLI_DEBUG=true
|
|
@@ -306,15 +348,15 @@ rubycli examples/fallback_example.rb scale --help
|
|
|
306
348
|
```
|
|
307
349
|
|
|
308
350
|
```text
|
|
309
|
-
Usage: fallback_example.rb scale
|
|
351
|
+
Usage: fallback_example.rb scale AMOUNT [FACTOR] [--clamp=<CLAMP>] [--notify]
|
|
310
352
|
|
|
311
353
|
Positional arguments:
|
|
312
|
-
AMOUNT
|
|
313
|
-
|
|
354
|
+
AMOUNT [Integer] required Base amount to process
|
|
355
|
+
FACTOR optional (default: 2)
|
|
314
356
|
|
|
315
357
|
Options:
|
|
316
|
-
--clamp
|
|
317
|
-
--notify
|
|
358
|
+
--clamp=<CLAMP> [String] optional (default: nil)
|
|
359
|
+
--notify [Boolean] optional (default: false)
|
|
318
360
|
```
|
|
319
361
|
|
|
320
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.
|
|
@@ -327,27 +369,35 @@ Here only `AMOUNT` is documented, yet `factor`, `clamp`, and `notify` are still
|
|
|
327
369
|
|
|
328
370
|
In short, comments never add live parameters by themselves; they enrich or describe what your method already supports.
|
|
329
371
|
|
|
330
|
-
##
|
|
372
|
+
## Argument parsing modes
|
|
373
|
+
|
|
374
|
+
### Default literal parsing
|
|
331
375
|
|
|
332
|
-
|
|
376
|
+
Rubycli tries to interpret arguments that look like structured literals (values starting with `{`, `[`, quotes, or YAML front matter) using `Psych.safe_load` before handing them to your code. That means values such as `--names='["Alice","Bob"]'` or `--config='{foo: 1}'` arrive as native arrays / hashes without any extra flags. Plain strings like `1,2,3` stay untouched at this stage (if the documentation declares `String[]` or `TAG...`, a later pass still normalises them into arrays), and unsupported constructs fall back to the original text, so `"2024-01-01"` remains a string and malformed payloads still reach your method instead of killing the run.
|
|
377
|
+
|
|
378
|
+
### JSON mode
|
|
379
|
+
|
|
380
|
+
Supply `--json-args` (or the shorthand `-j`) when invoking the runner and Rubycli will parse subsequent arguments strictly as JSON before passing them to your method:
|
|
333
381
|
|
|
334
382
|
```bash
|
|
335
|
-
rubycli
|
|
383
|
+
rubycli -j my_cli.rb MyCLI run '["--config", "{\"foo\":1}"]'
|
|
336
384
|
```
|
|
337
385
|
|
|
338
|
-
Programmatically you can call `Rubycli.with_json_mode(true) { … }`.
|
|
386
|
+
This mode rejects YAML-only syntax and raises `JSON::ParserError` when the payload is invalid, which is handy for callers who want explicit failures instead of silent fallbacks. Programmatically you can call `Rubycli.with_json_mode(true) { … }`.
|
|
339
387
|
|
|
340
388
|
## Eval mode
|
|
341
389
|
|
|
342
|
-
Use `--eval-args` to evaluate Ruby expressions before they are forwarded to your CLI. This is handy when you want to pass rich objects that are awkward to express as JSON:
|
|
390
|
+
Use `--eval-args` (or the shorthand `-e`) to evaluate Ruby expressions before they are forwarded to your CLI. This is handy when you want to pass rich objects that are awkward to express as JSON:
|
|
343
391
|
|
|
344
392
|
```bash
|
|
345
|
-
rubycli
|
|
393
|
+
rubycli -e scripts/data_cli.rb DataCLI run '(1..10).to_a'
|
|
346
394
|
```
|
|
347
395
|
|
|
348
396
|
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) { … }`.
|
|
349
397
|
|
|
350
|
-
`--eval-
|
|
398
|
+
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
|
+
|
|
400
|
+
`--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.
|
|
351
401
|
|
|
352
402
|
## Pre-script bootstrap
|
|
353
403
|
|