はじめに
この記事はMastodon
にRBS
を導入したときの導入背景や手順などをまとめた記事になります。
主に僕個人の備忘録としてまとめています。
導入背景
2017年5月から6年ほどCreatodon
というMastodon
のサーバーを個人的に運営しています。
gamelinks007.net
直近で開発環境周りの体験向上としてCIの修正とかE2Eテストの追加とか色々やっていたんですが、型関係はまだ手を入れていませんでした。
また独自機能の実装やそのメンテナンスなども行っており、既存のModel
やService
などの型情報が簡単に確認できる状況が欲しくもなっていました。
そこで
TypeProf
を使い、既存のModel
やService
などのRBS
を自動生成
- 既存のライブラリの型情報などは
gem_rbs_collection
を使って導入
Steep
で生成したRBS
の型情報をVS Code
で表示&型情報のチェック
までをMastodon
に導入してみました
やったこと
TypeProfを使い、既存のModelやServiceなどのRBSを自動生成
まずはMastodon
にある既存のModel
やService
、Contoroller
などの型をTypeProf
を使って自動生成しました。
コードとしては以下のような型の自動生成用タスクを追加して対応しました。
require 'fileutils'
top_level = self
using(Module.new do
refine(top_level.singleton_class) do
def generate_type_signature(dir_name)
files = Dir.glob("app/#{dir_name}/**/*")
files.each do |file|
next unless file.include?('.rb')
result = `bundle exec typeprof #{file}`
dir_name = File.dirname(file)
FileUtils.mkdir_p("sig/#{dir_name}")
File.write("sig/#{file}s", result)
end
end
end
end)
namespace :type do
namespace :prof do
task models: :environment do
generate_type_signature('models')
end
task controllers: :environment do
generate_type_signature('controllers')
end
task helpers: :environment do
generate_type_signature('helpers')
end
task lib: :environment do
generate_type_signature('lib')
end
task presenters: :environment do
generate_type_signature('presenters')
end
task serializers: :environment do
generate_type_signature('serializers')
end
task services: :environment do
generate_type_signature('services')
end
task validators: :environment do
generate_type_signature('validators')
end
task workers: :environment do
generate_type_signature('workers')
end
end
task prof: ['prof:models', 'prof:controllers', 'prof:helpers', 'prof:lib', 'prof:presenters', 'prof:serializers', 'prof:services', 'prof:validators', 'prof:workers']
end
あとは欲しい場所(Model
ならbundle exec rake type:prof:models
のような感じで)の型情報をタスクとして実行すればOKです。
既存のライブラリの型情報などはgem_rbs_collectionを使って導入
次に既存のライブラリの型情報をgem_rbs_collection
を使って導入しました。
こちらのドキュメントを参考に以下のコマンドを実行。
rbs collection init
実行するとrbs_collection.yaml
が生成されます。これを以下のように変更しています。
# Download sources
sources:
- type: git
name: ruby/gem_rbs_collection
remote: https://github.com/ruby/gem_rbs_collection.git
revision: main
repo_dir: gems
# You can specify local directories as sources also.
# - type: local
# path: path/to/your/local/repository
# A directory to install the downloaded RBSs
path: .gem_rbs_collection
gems:
# Skip loading rbs gem's RBS.
# It's unnecessary if you don't use rbs as a library.
- name: rbs
ignore: true
- name: steep
ignore: true
- name: ipaddr
変更内容としては後述するSteep
での型チェック時にパスするために必要なライブラリの設定だけ追加してる感じです。
あとは.gem_rbs_collection
を.gitignore
に追加して、以下のコマンドを実行するだけです。
rbs collection install
これで既存のライブラリの型情報が導入できました。
次にSteep
を導入し、TypeProf
とgem_rbs_collection
で導入した型情報をVS Code
上に表示させます。
まずはGemfile
にSteep
を追加してbundle install
を実行。
gem 'steep'
その後bundle exec steep init
を実行して、設定ファイルを生成します。
bundle exec steep init
生成されたSteepfile
を以下のように変更します。
target :app do
check 'app'
signature 'sig'
end
check
には型情報をチェックしたい場所のディレクトリを指定し、signature
にRBS
があるディレクトリを指定している感じです。
あとは以下のVS Code
のExtension
をインストールし、VS Code
を再起動すればOKです。
github.com
再起動すると以下の画像のように型情報が表示されているかと思います。
型チェックがパスするように修正
次にbundle exec steep check
がパスするように修正しました。
やったこととしては
- デフォルトの設定だと大量のエラーが出るので一時的にIgnore
TypeProf
で生成された一部のRBS
での型情報が正しくないと表示されたのを修正
app/lib
配下の一部のコードで重複エラーが返されたので修正
という感じです。
エラーを一時的にIgnoreするのは以下のようにSteepfile
を修正しました。
ignores = [
Steep::Diagnostic::Ruby::MethodDefinitionMissing,
Steep::Diagnostic::Ruby::UnknownConstant,
Steep::Diagnostic::Ruby::NoMethod,
Steep::Diagnostic::Ruby::UnexpectedBlockGiven,
Steep::Diagnostic::Ruby::IncompatibleAssignment,
Steep::Diagnostic::Ruby::UnknownInstanceVariable,
Steep::Diagnostic::Ruby::UnexpectedPositionalArgument,
Steep::Diagnostic::Ruby::UnresolvedOverloading,
Steep::Diagnostic::Ruby::InsufficientPositionalArguments,
Steep::Diagnostic::Ruby::UnknownGlobalVariable,
Steep::Diagnostic::Ruby::UnexpectedError,
Steep::Diagnostic::Ruby::MethodBodyTypeMismatch,
Steep::Diagnostic::Ruby::ArgumentTypeMismatch,
Steep::Diagnostic::Ruby::UnsupportedSyntax,
Steep::Diagnostic::Ruby::UnsupportedSyntax,
Steep::Diagnostic::Ruby::UnexpectedSuper,
Steep::Diagnostic::Ruby::UnexpectedYield,
Steep::Diagnostic::Ruby::BreakTypeMismatch,
Steep::Diagnostic::Ruby::RequiredBlockMissing,
Steep::Diagnostic::Ruby::ReturnTypeMismatch,
Steep::Diagnostic::Ruby::ImplicitBreakValueMismatch,
]
target :app do
check 'app'
signature 'sig'
configure_code_diagnostics do |hash|
ignores.each do |ignore|
hash[ignore] = :information
end
end
end
あとTypeProf
で生成されたRBSの型情報が正しくない件については、以下のようなRange
が返ってくると期待されているものでエラーが返ってきました。
def show: -> Range
現状では泣く泣くuntyped
に置き換えて、一旦パスするようにしています......。
def show: -> untyped
app/lib
配下のコードの重複エラーについては以下のように対応しました。
def current_time: -> Float
| ...
今後
おおよその型情報についてはTypeProf
とgem_rbs_collection
のおかげでなんとかなっていますが、untyped
なままのものも多い状況です。
なので、この辺を少しづつ片付けていきたいですねー。
参考
github.com
github.com
github.com
github.com
techlife.cookpad.com
pocke.hatenablog.com
github.com
zenn.dev
sinsoku.hatenablog.com
pocke.hatenablog.com
joker1007.hatenablog.com