2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

typeprof で自分の書いたコードの間違いが分かるようにしたい

Posted at

はじめに

typeprof でソースコードの解析を行うと、自分の間違いとは関係のないエラーも出力されることがあります。

自分の知りたい間違いだけが出力されるようにするために、安直なツールを作成しました。

tpoutcut

興味のないエラーを取り除いてもまだエラーが残っていれば、終了コードでそれがわかる、というものです。

たとえば

間違いのあるコード

以下のコードには間違いが 2 つあります。

app/tpoutcut.rb
class Tpoutcut
  def run
    app_params = AppParams.load
    result = make_result(app_params)

    puts result.contents

    make_exit_code(result_data)
  end

  private

  def make_result(app_params, _mode)
    result = Result.new(config: app_params.config)

    InputFile.open(app_params.input_path) do |file|
      file.each do |line|
        line.gsub!(/[\r\n]*$/, '')
        result.update(line)
      end
    end

    result
  end

  def make_exit_code(result)
    result.contents.empty? ? 0 : 1
  end
end

間違いは以下の 2 点です。

  • make_result メソッド定義ではの引数が 2 つあるのに、呼び出し側が 1 つしか指定していない。
  • make_exit_code メソッドの呼び出しで未定義の変数 result_data を参照している。

Rubocop で試す

社内では Rubocop を活用しています。これらの間違いを Rubocop で検出できるでしょうか。

$ bundle exec rubocop --require rubocop-rspec app/tpoutcut.rb
Inspecting 1 file
.

1 file inspected, no offenses detected

検出されませんでした。Rubocop は Linter の役割を果たすものであり、ロジックの間違いは検出されません。

typeprof で試す

Ruby 3.0 以降では、静的解析のツールとして、typeprof があります。試してみます。

$ typeprof --show-errors app/tpoutcut.rb
# TypeProf 0.21.3

# Errors
  : (中略)
app/tpoutcut.rb:11: [error] wrong number of arguments (given 1, expected 2)
app/tpoutcut.rb:15: [error] undefined method: Tpoutcut#result_data
  : (中略)

# Classes
  : (以下省略)

出力内容の # Errors セクションに、見つけたい間違いが出力されています。テストコードを書いていなくても間違いが検出されました。

typeprof を単独で実行した場合

困る:無視してもよさそうなエラー出力がある

typeprof を実行してみます。

$ typeprof --show-errors typeprof.rbs app/*.rb
# TypeProf 0.21.3

# Errors
app/config.rb:13: [error] undefined method: singleton(YAML)#safe_load
app/config.rb:14: [error] unknown keyword: 
app/result.rb:11: [warning] inconsistent assignment to RBS-declared variable
app/tpoutcut.rb:11: [error] wrong number of arguments (given 1, expected 2)
app/tpoutcut.rb:15: [error] undefined method: Tpoutcut#result_data

# Classes
  : (以下省略)

出力されたエラー内容のうちいくつかは、無視してもよさそうです。「YAML に safe_load メソッドはない」などは、知らんがな、と言いたいところです。

ちょっと困る:終了コードは変わらない

typeprof は型推論をするツールであって、少なくとも現時点では、間違いを検出するためのものではなさそうです。実行結果に # Errors のセクションがあってもなくても、終了コードは 0 になりました。

$ typeprof --show-errors typeprof.rbs app/*.rb
  :

$ echo $?
0

つまり

  • 興味のないモジュールについてのエラーは出力内容から除外できる
  • エラーが見つかったことが終了コードでわかる

これができれば実用的になりそうです。

tpoutcut

実行してみる

typeprof の実行結果は標準出力に出力されているので、これを読み取って、必要な部分だけ抜き出します。

tpoutcut のリポジトリが ~/projects にあるとします。

$ PATH=$PATH:~/projects/tpoutcut/bin

$ typeprof --show-errors typeprof.rbs app/*.rb | tpoutcut

たとえば以下のような内容が出力されます。# Errors セクションの内容だけが取り出されました。

app/config.rb:13: [error] undefined method: singleton(YAML)#safe_load
app/config.rb:14: [error] unknown keyword: 
app/result.rb:11: [warning] inconsistent assignment to RBS-declared variable
app/tpoutcut.rb:11: [error] wrong number of arguments (given 1, expected 2)
app/tpoutcut.rb:15: [error] undefined method: Tpoutcut#result_data

自前でやらなくても、typeprof コマンドのオプション引数で # Errors の内容だけを出力できるのかもしれませんが、わかりませんでした。

除外したいエラーを定義する

設定ファイルを用意します。出力内容から除外したいエラー内容の正規表現パターンを指定します。

sample/sample01.yaml
section: Errors
excludes:
  - '\[warning\]'
  - 'undefined method: singleton\(YAML\)#safe_load'
  - 'app/config.rb:[\d]+: \[error\] unknown keyword: '

設定ファイルを指定して実行します。

$ typeprof --show-errors typeprof.rbs app/*.rb | tpoutcut --config "$(pwd)/tpoutcut.yaml"

以下のように実行結果が変わります。

app/tpoutcut.rb:11: [error] wrong number of arguments (given 1, expected 2)
app/tpoutcut.rb:15: [error] undefined method: Tpoutcut#result_data

検出したいエラーだけが出力されました。

終了コードを確認する

間違いが残っている状態で tpoutcut を実行すると、すなわち、# Errors セクションに、除外対象ではないエラー内容が残っていると、終了コードは 1 になります。

$ typeprof --show-errors typeprof.rbs app/*.rb | tpoutcut --config "$(pwd)/tpoutcut.yaml"
app/tpoutcut.rb:11: [error] wrong number of arguments (given 1, expected 2)
app/tpoutcut.rb:15: [error] undefined method: Tpoutcut#result_data

$ echo $?
1

間違いを修正してから実行すると、終了コードが 0 になります。

$ typeprof --show-errors typeprof.rbs app/*.rb | tpoutcut --config "$(pwd)/tpoutcut.yaml"

$ echo $?
0

これで、自分の知りたい書き間違いを検出することができるかもしれません。

おわりに

RBS を使用した静的型解析に Steep がありますが、すみません、まだ触っていません。今回は typeprof だけ見てみました。

Ruby でよく間違えるのは、メソッドの引数を増やしたのに呼び出し元は直していなかったとか、変数名が間違っているとか、そういうところになるかと思いますが、それをテストコードなしで検出できるのであれば、心強いです。

他のツールも見ながら、安全な開発ができるようにしていきたいです。

参考

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?