Open13

既存rails projectにrbs/steepを導入する

paihupaihu

gemの追加

 bundle add --group development --require false  steep rbs_rails
paihupaihu

rbs collection のインストール

bundle exec rbs collection init
bundle exec rbs collection install

標準で .gem_rbs_collection ディレクトリにインストールされるので
.gitignore に .gem_rbs_collection を追加しておくと良い

paihupaihu

rbs_rails の rake task 作成

lib/tasks/rbs.rake ファイルを下記内容で作成

require 'rbs_rails/rake_task'

RbsRails::RakeTask.new
paihupaihu

rbs_rails の rake task 実行(これはmodelが更新されるたびに実行すると良い)

bin/rails rbs_rails:all

sig/rbs_rails/ に rbs ファイルが生成されるので、覗いてみる。

rake task は定期的に実行されるので、 sig/rbs_rails/ 以下のファイルには手動修正は行わない。

paihupaihu

Steepfile の作成

下記コマンドでひな形を生成(ドキュメント目的)

bundle exec steep init

Steepfile に下記内容を追加する

target :app do
  signature "sig" # rbs file directory
  check "app" # target diregtory

  collection_config "rbs_collection.yaml" # rbs collection のインストールで作成されたファイル
end
paihupaihu

これで

bundle exec steep check

でチェックできるようになった。
VSCodeに steep extension をインストールすると、VSCode でも利用できる。

paihupaihu

既存コードのプロトタイプ一括生成

sig/rbs_rails に rbs_rails の生成したrbsファイルがあるので、ディレクトリを分ける。

find app -type d | xargs -S1000 -I{}  bundle exec rbs prototype rb {}/*.rb -o sig/app/

sig/local/app みたいにもう1階層掘るのも良いかも

paihupaihu

日本語が混じっているとrbs prototypeがそのまま出して エラーになるので

生成されたrbsファイルに日本語が混じっていれば修正する。

例えば

alias 日本語 aliased_method

みたいなのがあれば

alias `日本語` aliased_method

のように書き換える

同様に

def method: (日本語: untyped) -> untyped

def method: (`日本語`: untyped) -> untyped

のように置き換える

この挙動はbugの様な気もしたので issue をたてた。https://github.com/ruby/rbs/issues/1194

修正箇所は

https://github.com/ruby/rbs/blob/69743cedda03cfdaaf7cc8fb52ad48f4a489eb78/lib/rbs/types.rb#L980-L986

https://github.com/ruby/rbs/blob/69743cedda03cfdaaf7cc8fb52ad48f4a489eb78/lib/rbs/writer.rb#L229-L230

このあたりか?

paihupaihu

あとは、定義がなくてエラーの出る個所をひたすら型定義していく。gemファイルのものは

sig/gems/... のようなディレクトリに置いたりすると、自分たちのコードや自動生成されたものとも分けられてよい。

他所のgemのrbsファイルが上手くつくれたらrbs_collectionにPRを出して貢献していくのがいいと思う

paihupaihu

ActiveRecord::TimeWithZone型(ActiveRecordのupdated_atなど)にDateTimeやTimeを入れていると型違いでエラーになるので

in_time_zone() をつけて TimeWithZone に明示的に変換してまわる。

paihupaihu

たまに刺さるファイルがあるので --verbose とかでファイルを特定して
Steepfileに

ignore(
"該当ファイル1",
"該当ファイル2",
)

なとどしていったん除外する。

paihupaihu

VSCode Steep で余計な警告を出さないようにignoreしたものたち

  configure_code_diagnostics do |hash|
    hash[D::Ruby::NoMethod] = nil
    hash[D::Ruby::FallbackAny] = nil
    hash[D::Ruby::UnknownInstanceVariable] = nil
    hash[D::Ruby::MethodDefinitionMissing] = nil
    hash[D::Ruby::UnknownConstant] = nil 
    hash[D::Ruby::UnexpectedError] = nil 
    hash[D::Ruby::UnexpectedSuper] = nil 
    hash[D::Ruby::IncompatibleAssignment] = nil
    hash[D::Ruby::UnexpectedBlockGiven] = nil 
    hash[D::Ruby::UnexpectedKeywordArgument] = nil 
    hash[D::Ruby::UnexpectedPositionalArgument] = nil 
    hash[D::Ruby::InsufficientKeywordArguments] = nil 
    hash[D::Ruby::UnresolvedOverloading] = nil 
    hash[D::Ruby::UnexpectedJump] = nil 
  end