圧倒亭グランパのブログ

30年後の自分にもわかるように書くブログ

Crystalのcli紹介 "tool expand"

この記事は、 Crystal Advent Calendar 2017 の13日目の記事です。

crystalのcliには便利なサブコマンドやオプションがあります。コーディングを支えるものだったり、build時の細かな設定だったりします。知っていると得をする、だけど知らない人も多いかもしれない。そんなサブコマンドやオプションを紹介します。

  

今回は、 $ crystal tool expand を紹介します。

tool expand

まずはcliのhelpを見てみましょう。

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

Tool:
    context                  show context for given location
    expand                   show macro expansion for given location
    format                   format project, directories and/or files
    hierarchy                show type hierarchy
    implementations          show implementations for given call in location
    types                    show type of main variables
    --help, -h               show this help

expand があります。

show macro expansion for given location

macroを展開してくれるコマンドです。expandのhelpも見てみましょう。

$ crystal tool expand --help
Usage: crystal tool expand [options] [programfile] [--] [arguments]

Options:
    -D FLAG, --define FLAG           Define a compile-time flag
    -c LOC, --cursor LOC             Cursor location with LOC as path/to/file.cr:line:column
    -f text|json, --format text|json Output format text (default) or json
    --error-trace                    Show full error trace
    -h, --help                       Show this message
    --no-color                       Disable colored output
    --prelude                        Use given file as prelude
    -s, --stats                      Enable statistics output
    -p, --progress                   Enable progress output
    -t, --time                       Enable execution time output

よく使うのは-cオプションです。カーソルの位置をファイルパス:行数:列数と指定することで、その位置のmacroを展開してくれます。

例を見てみましょう。ちょうど先週のアドベント・カレンダーでmacroを取り扱ったので、そのコードで試してみます。

class User
  def initialize(@name : String, @age : Int32)
  end

  def_equals @name, @age
end

このファイルに対して以下のコマンドを打つと、macro部分が展開されます。(5行7列はdef_equalseの位置です)

$ crystal tool expand -c src/def_equals_expand.cr:5:7 src/def_equals_expand.cr
1 expansion found
expansion 1:
   def_equals(@name, @age)

~> def ==(other : self)
     if @name == (other.@name)
     else
       return false
     end
     if @age == (other.@age)
     else
       return false
     end
     true
   end

カーソル位置でmacroが発見され、それが展開されました。既存のmacroの実装を確認することができます。

とはいえ、このexpand の活躍する場は、何と言っても「macroを書いているとき」です。このコマンドが無かった時は、展開後のmacroがどうなるかを知る術はありませんでした。build時に出るエラーだけが頼りでした。

実はこのexpandは、渋谷で開かれたCrystal勉強会が発端です。「macro書きづらいよね」という話を懇親会で行っていたところ、Crystalのハードコアなコントリビューターである make_now_justさんが後日実装されたのです。それがすぐに本家に取り込まれ、正式なtoolとなりました。toolの生まれる瞬間を目の当たりにしていたので、自分もexpandはなんだか好きです。

通常はエディタから叩くことが多いでしょう。ファイルパス:行数:列数 というインターフェースになっているので、設定はし易いと思います。

「macroのハードル高い...」と思っている方は、ぜひ使ってみてください。