D言語（rdmd）はスクリプト用途にめっちゃ便利

# rdmd めっちゃ便利

`rdmd` とはD言語をスクリプト風に使えるツールである。コンパイラを入れれば大体付いてくる。めっちゃ便利である。

これはD言語のコードを `build.d` などに書いて、 `rdmd build.d` とするだけでプラットフォーム非依存なスクリプトとして動かせる。めっちゃ便利である。

たとえば `docker build -t testapp .` としたいなら、 

```d:build.d
import std;
void main() {
    spawnShell("docker build -t testapp .").wait();
}
```
で良い。見るからに普通のD言語である。
もしも `push` までしたいなら、イメージ名あたり変数にして2行書けば良い。めっちゃ単純である。

さてWindowsで同じようなことをしようとした各位、 `.bat` か `.cmd` で悩んだ時間がもう無駄となる。
どうせ変数宣言の `SET` 程度しか覚えておらず、文法確認に時間を要し、変数の末尾に文字列を付けたいだけの処理でパス区切り有無を間違うのだ。これが先日の私。
もうファイルをダブルクリックで実行できるメリットなど、文法と一緒に忘れるべきである。頼むからせめてPowerShellにしよう。

---
さらに `rdmd build.d` は `rdmd build` と書くことができる。拡張子が取れるだけだが、これが控えめに言ってめっちゃ実用的である。

ここで `rdmd start` や `rdmd test` などと書き始めると、Web開発でよく見る `npm start` っぽいと感じる人も出てくるだろう。

すると、どんなコマンドを用意すると便利なのか、他の業界知識も転用できるようになってくる。
人間勘が働くようになると成長も速い。これはもう一気に実用的に見える。

そしてこれもサブルーチン的に組み合わせることができる。こうなるとかなり実践的である。

たとえば `rdmd lint` で文法チェックし、 `rdmd build` でビルドし、 `rdmd publish` で `git push` などとまとめて呼ぶと良い感じになる。
ちなみに `dub lint` というコマンドがあるのは覚えておきたい。

そして書くのは大体 `spawnShell` で良い。標準入出力が既定でリダイレクトされるのでプログラムを直接実行したのと同じように使える。
相手が `git` でも `dub` でも、これだけでしばらく戦っていられる。

```d:publish.d
import std;
void main() {
    spawnShell("rdmd lint").wait();
    spawnShell("rdmd build").wait();
    spawnShell("git push").wait();
}
```

あとはステータスコードを見て処理を抜けたりしたいこともある。これは普通に `if` 文が書ける。

```d:
import std;
void main() {
    auto status = spawnShell("docker build -t testapp .").wait();
    if (status != 0) {
        stderr.writeln("ビルドエラー！ステータス : ", status);
        return;
    }
    spawnShell("docker run -it --name testapp testapp").wait();
}
```

当然だが、ここで何か `0` でない値を受け取ったら例外を投げる関数を書いても良い。これはもう普通にD言語なので強い部分である。

---

さらに `rdmd` はコマンドライン引数も扱える。
さて、従来 bash と bat でどうやって引数を使っていたか覚えているだろうか？

正解は、bat なら `$0, $1, ...` で bash なら `%0, %1, ...` である、というのは嘘で逆である。すぐに違和感があった人はかなりのツワモノだろう。

しかしD言語なら調べるまでもなく、大体手癖か勘で `string[] args` と書ける。いつもと同じである。

```d:print.d
import std;
void main(string[] args) {
    writeln(args);
}
```

これに思った通りに引数を渡せば良い。悩む余地はほとんどない。

```console:実行
rdmd print a b c
```

結果は普段の各スクリプトと同じで、先頭要素がパスになっているのは案外忘れがちである。そしてここがNode.jsやRubyだと少し違うので結構引っかかる。

```console:結果
["C:\...\print.exe", "a", "b", "c"]
```

またD言語の標準ライブラリには `std.getopt` という引数解析モジュールもあるので、外部ライブラリがなくとも引数が容易に扱える。

スクリプトがあまり複雑になっても良くないが、困ったら日本語の [Cookbook(コマンドライン解析)](https://dlang-jp.github.io/Cookbook/cookbook--getopt_example.html) あたりも見てほしい。

---

そもそもだが、よくある手順のスクリプト化というのは `rdmd` など関係なく重要である。

しかし、その重要さとD言語の強みには重なる部分が多くあるので挙げておく。良いこと尽くしである。

- スクリプトは人に引き継ぐことも多いため、誰でもすぐ読み書きできることが求められる。
    - 学習曲線が緩いD言語はすぐに扱えると期待できる。特に C/C++/C#/Java あたりの経験者は初見でも大体読めるのが強い。

- 昨今はOSSを筆頭に、作ったプログラムが様々な環境で動くことを求められる。ここでWindowsとLinuxで別スクリプトを用意するのは結構な手間である。
    - 複数プラットフォームをカバーするD言語ならスクリプトは当然1つで済む。jsやrubyが強いのは言うまでもないが、ここでWSL前提にbash大統一の時代はまだ来ていない。

- スクリプトは開発中に何度も実行するので、実行も高速なほうが好ましい。
    - D言語はデバッグ実行でも高速なスクリプト言語並か、より高速なことが多い。実際は一度実行ファイルが作られるので、繰り返し実行が特に強い。一部の言語は不得意な処理(再帰など)もあるので要注意。

- スクリプトは整備中、頻繁に書き換えて実行する。コンパイル不要が理想的で、そうでなければ相当速くないと困る。
    - D言語のコンパイルは非常に高速なので困ることはほぼない。 `spawnProcess` 連打程度なら、100行あってもコンパイルは1秒程度で済む。実行時間と合わせれば速くなることもあり、ほとんどは誤差と区別がつかない。

D言語で開発していれば言語学習のコストも減るうえ、ツールがコンパイラ付属なので環境構築も楽で複数プラットフォーム対応も容易になる。
つまりD言語はめっちゃ便利で実用的である。

ここまで便利なのになぜ誰も教えてくれなかったのか、今までの時間を返してほしいという2021年梅雨の思い出を元にしたポエムである。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">えー、bat/cmdファイル頑張ってたのをrdmdで代替するようにしたらめっちゃ便利なんだけど…今までの時間を返して…</p>&mdash; lempiji@思秋期 (@lempiji) <a href="https://twitter.com/lempiji/status/1404779036388122624?ref_src=twsrc%5Etfw">June 15, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# 参考
- 公式インストール
    - https://dlang.org/download.html
- rdmdコマンドラインリファレンス
    - https://dlang.org/rdmd.html