圧倒亭グランパのブログ

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

Crystalのcli紹介 "tool context"

この記事は、 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      |

このスコープにある変数一覧と型が表示されました。ここでふと気づくのが、iv1iv2があることです。コード上では存在していません。

実は、@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 、ぜひ使ってみてください。