crystalコマンドでハマった罠

最初に

正直、Crystalで大きめなコードをまだほぼ書いたことがなく、
ブラウザでCrystalを書いて実行することも多く、 crystalコマンドについてあまり理解しておらず、ちょっとハマったことを書く。

最初にcrystalコマンドの説明を見てみる

多くのコマンドがそうであるようにcrysltal --helpとすれば、
crystalコマンドの簡単な説明を得ることができる。 crystal -hcrystal helpでもよい。

$ crystal --help
Usage: crystal [command] [switches] [program file] [--] [arguments]

Command:
    init                     generate a new project
    build                    build an executable
    docs                     generate documentation
    env                      print Crystal environment information
    eval                     eval code from args or standard input
    play                     starts Crystal playground server
    run (default)            build and run program
    spec                     build and run specs (in spec directory)
    tool                     run a tool
    help, --help, -h         show this help
    version, --version, -v   show version

Run a command followed by --help to see command specific information, ex:
    crystal <command> --help

これを見ると、それぞれのコマンドの説明が見れる。
「run (default)」と書いてあり、サブコマンドを省略するとrunが適用されるようにみえる。
しかし、これには罠があり、省略するとオプションの扱いが変わってくるので全く同じではない。

なお、このhelpの説明を見ると、「crystal --help」とあり、
crystal run --helpの形でサブコマンドのもう少し詳しい説明を読むことができる。

コンパイラの使い方 - Crystal
なお、日本で詳しい説明を見たければ、上記のページを見ればよさそう。

runコマンドの有無の違い

crystal run foo.cr --release
crystal foo.cr --release

自分は、上と下が同じだと思って罠にハマった。
上のrunコマンドで呼び出した場合は、--releaseオプションが機能する。
しかし、下の場合は、--releaseオプションが機能しなかった。

これについて、CrystalコミュニティのDiscordで雑に尋ねてみたところ、
z64さんという方に「昔はrunコマンドなしで、--releaseオプションが機能した」と教えてもらった。
なぜ削除したのか質問してみたが、正確に覚えてないとのことだった。
ただcrystal foo.cr --releaseの場合は、crystalコマンドのオプションではなく、ファイルのオプションとして認識されるということだった。

{% if flag?(:release) %}
  puts ["flag release", ARGV]
{% else %}
  puts ["flag no release", ARGV]
{% end %}

上記の内容のファイルを作り、比べてみると分かりやすい。
ここでは、foo.crというファイル名にした。

$ crystal run foo.cr --release
["flag release", []]

$ crystal foo.cr --release 
["flag no release", ["--release"]]

runコマンドの方は、crystalコマンドのオプションとして--releaseが認識されていてflag?マクロで認識できるがARGVには残っていない。
対して、runを省略した場合は、crystalコマンドのオプションとして認識されずARGVに残る。

というわけで、上記のような違いがあった。

まとめ

最初はrun省略時に何も認識されてないように見えて修正されるべきバグか何かだと思ったが、
聞いてみるとファイルのオプションとして認識されているとのことだった。
初見殺しな感じもしてわかりにくい気もするが、何か使い分けできるかもしれないので、もしかしたら便利かもしれない。