Nimで簡単にマルチコマンドCLIツールを作りたい

# はじめに
社内でちょっとしたCLIツールを作るという話になった為、私の推し言語Nimで作ることに。
NimのCLIツールを簡単に作れるフレームワークcligenを使用します。
いろんな方が既に使いかたについての記事を書いていますが、サブコマンドがあるCLIの詳しい作成方法を書いた記事が少ないのと、自分の躓いた部分の備忘録としてcligenの使い方を残しておきます。

リポジトリ

https://github.com/c-blake/cligen/tree/master

# インストール
nimbleを使用してインストール。
`nimble install cligen`

# とりあえず使ってみる
### コマンドにしたい関数を定義する
今回はマルチコマンドのCLIツールを作成するため2つ定義します。
```nim
proc hoge(opt1: string, opt2: string = "English"): int =
  ## これはhogeの説明です。
  echo "Hello"
  return 0
    
proc fuga(): int =
  ## これはfugaの説明です。
  echo "Goodbye"
  return 0

```
関数の引数がそのままオプションになります。
また、デフォルト値を設定することによってそのオプションを任意にすることができます。
デフォルト値を設定しない引数は必須になります。
戻り値は終了コードとして使用します。

### コマンドとして実装

```nim:hoge_fuga_commands.nim
import cligen

when isMainModule:
  dispatchMulti(["multi"],
                [hoge1, help = {"opt1":"オプション1の説明",
                                "opt2":"オプション2の説明"}],
                [hoge2]
                )
```
`["multi"]`とすることでメインコマンドのヘルプを提供することができます。

```bash:実行結果
$ ./hoge_fuga_commands
これはhogeの説明です。
Usage:
  hoge_fuga_commands {SUBCMD}  [sub-command options & parameters]
where {SUBCMD} is one of:
  help   print comprehensive or per-cmd help
  hoge  これはhogeの説明です。
  fuga  これはfugaの説明です。

hoge_fuga_commands {-h|--help} or with no args at all prints this message.
hoge_fuga_commands --help-syntax gives general cligen syntax help.
Run "hoge_fuga_commands {help SUBCMD|SUBCMD --help}" to see help for just SUBCMD.
Run "hoge_fuga_commands help" to get *comprehensive* help.
```
それっぽくなってはいますが、ヘルプが色々とおかしいと思います。
基本的に何も指定がない場合、cligenはライブラリの中の`cligen/usage.nim`をそのまま使用するため、プロジェクトディレクトリで`usage.nim`を定義してやる必要があります。

### `usage.nim`を定義
```nim:usage.nim
const clUseHdr* = "Usage:\n  " 

const clUse* = "$command $args\n${doc}Options:\n$options"

const clUseMultiGeneral* = """
$command {-h|--help} または引数なしでこのメッセージを表示します。
$command --help-syntax は一般的な cligen の構文ヘルプを提供します。
"$command {help サブコマンド|サブコマンド --help}" を実行して、サブコマンドのヘルプのみを表示します。
"$command help" を実行すると、包括的なヘルプを表示することができます。"""

const clUseMulti* = """${doc}Usage:
  $command {SUBCMD}  [sub-command options & parameters]
where {SUBCMD} is one of:
$subcmds
""" & clUseMultiGeneral

const clUseMultiPerlish* = """hoge_fuga_commands
${doc}使用方法
  $command {サブコマンド}  [サブコマンドのオプションとパラメーター]

サブコマンド
$subcmds
----------------------------------------------------------------
""" & clUseMultiGeneral
```
ライブラリの中の`usage.nim`の内容をそのまま日本語訳して、少し見やすく整えました。

### コマンドの実装部分の修正
内容を修正した`usage.nim`を`hoge_commands.nim`から`include`を使って呼び出します。

```nim:hoge_fuga_commands.nim
import cligen
include usage

when isMainModule:
  dispatchMulti(["multi", doc ="hoge_fuga_commands", usage = clUseMultiPerlish],
                [hoge, help = {"opt1":"オプション1の説明",
                                "opt2":"オプション2の説明"}],
                [fuga]
                )
```
`doc`で説明欄の使用方法の部分のツール名を指定できます。
`usagusage = clUseMultiPerlish`でusage.nimで設定した説明を表示できます。

```bash:実行結果
$ ./hoge_fuga_commands 
hoge_fuga_commands
  hoge_fuga_commands使用方法
  hoge_fuga_commands {サブコマンド}  [サブコマンドのオプションとパラメーター]

サブコマンド
  help   print comprehensive or per-cmd help
  hoge  これはhogeの説明です。
  fuga  これはfugaの説明です。

----------------------------------------------------------------
hoge_fuga_commands {-h|--help} または引数なしでこのメッセージを表示します。
hoge_fuga_commands --help-syntax は一般的な cligen の構文ヘルプを提供します。
"hoge_fuga_commands {help サブコマンド|サブコマンド --help}" を実行して、サブコマンドのヘルプのみを表示します。
"hoge_fuga_commands help" を実行すると、包括的なヘルプを表示することができます。

```
設定したマルチコマンドのヘルプメッセージを表示することができました。

### 実際にサブコマンドを動かしてみる
```bash:実行結果
$ ./hoge_fuga_commands hoge -o:test
Hello

$ ./hoge_fuga_commands fuga
Goodbye
```

# まとめ
日本語のドキュメントが少ないため、躓く部分が多かったです。
Nimのわかりやすい構文で、関数をそのままコマンドにできるためちょっとした社内ツール開発には使えるなと思いました。
Nimはまだまだコミュニティが小さく発展途上ですが、とても魅力的な言語だと思うのでちょっとしたプロジェクトなどで触っていきたいなと思います。

参考
[NimのCLIツール作成用ライブラリcligenがとても便利](https://qiita.com/jiro4989/items/d5476b3dce3c4b3d6523)

# PR
ニッチな言語での開発もGOを出してくれるナイスな会社です。
そんなナイスな会社で一緒に働いてくれる方を募集しています。
詳しくは下記URLをご覧ください。

https://www.wantedly.com/companies/company_1271213