この記事は、 Crystal Advent Calendar 2017 の15日目の記事です。
crystalのcliには便利なサブコマンドやオプションがあります。コーディングを支えるものだったり、build時の細かな設定だったりします。知っていると得をする、だけど知らない人も多いかもしれない。そんなサブコマンドやオプションを紹介します。
今回は、 $ crystal tool context を紹介します。
tool context
まずは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
context があります。
show context for given location
現在位置のスコープの情報を出力してくれるコマンドです。contextのhelpも見てみましょう。
$ crystal tool context --help
Usage: crystal tool context [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オプションです。カーソルの位置をファイルパス:行数:列数と指定することで、その位置のスコープ情報を出力してくれます。
例を見てみましょう。下記のファイルを用意します。
src/context.cr
module Context class MyClass def initialize(@iv1 : String, @iv2 : String) @iv3 = [@iv1, @iv2] # cursor1 end def my_method lv1 = 1 lv2 = 1.1 lv3 = [1, 2] lv4 = [lv1, lv2, lv3, @iv3] # cursor2 lv4 end end end c = Context::MyClass.new("hoge", "fuga") p c.my_method
コマンドを打ってみます。5:7は# cursor1の部分です。
$ crystal tool context -c src/context.cr:5:7 src/context.cr 1 possible context found | Expr | Type | --------------------------- | self | Context::MyClass | | @iv1 | String | | @iv2 | String | | @iv3 | Array(String) | | iv1 | String | | iv2 | String |
このスコープにある変数一覧と型が表示されました。ここでふと気づくのが、iv1とiv2があることです。コード上では存在していません。
実は、@iv1や@iv2に直接代入する構文、
def initialize(@iv1 : String, @iv2 : String)
ここでは一度local変数に代入されているのです。試しにローカル変数を表示してみましょう。
...
def initialize(@iv1 : String, @iv2 : String)
@iv3 = [@iv1, @iv2]
p iv1
# cursor1
end
...
出力は以下です。
$ crystal run src/context.cr "hoge" [1, 1.1, [1, 2], ["hoge", "fuga"]]
hogeが出力されているので、ローカル変数iv1が存在していることになります。contextを見てみることで、このような気付きを得ることができました。
ちなみに# cursor2の位置でcontextを実行すると以下になります。
$ crystal tool context -c src/context.cr:13:7 src/context.cr 1 possible context found | Expr | Type | ---------------------------------------------------------------- | self | Context::MyClass | | @iv1 | String | | @iv2 | String | | @iv3 | Array(String) | | lv1 | Int32 | | lv2 | Float64 | | lv3 | Array(Int32) | | lv4 | Array(Array(Int32) | Array(String) | Float64 | Int32) |
ローカル変数に加え、インスタンス変数もしっかりとスコープ内に存在します。
$ crystal tool context 、ぜひ使ってみてください。