rbs-inline をチーム内に導入するにあたって、 watch してビルドするための仕組みを整えた。
rbs-inline の README には fswatch -0 lib | xargs -0 -n1 bundle exec rbs-inline --output
が紹介されている。
ただ、この方法だと fswatch を各々インストールする必要がある。 (チーム開発では、セットアップを複雑にしたくない、等で外部ツールに依存したくないことがある)
代わりに listen gem を使って Ruby 内で完結するようにした。実際の watch するコードは ↓ の感じ。
namespace :rbs do
TARGET_DIRS = %w(app lib).freeze
desc 'Build RBS files automatically on file changes'
task watch: :build do
require 'listen'
listener = Listen.to(*TARGET_DIRS, only: /\.rb$/) do |modified, added, removed|
if removed.present?
warn "#{removed} are removed. Rebuilding all RBS files..."
Rake::Task['rbs:rebuild'].execute
elsif modified.present? || added.present?
warn "#{modified + added} are modified. Build RBS files from these files..."
sh('bundle', 'exec', 'rbs-inline', '--output', '--opt-out', *modified, *added)
end
end
listener.start
sleep
ensure
listener&.stop
end
desc 'Build RBS files from inline annotations in Ruby files'
task :build do
sh("bundle exec rbs-inline --output #{TARGET_DIRS.join(' ')}")
end
desc 'Rebuild all RBS files'
task :rebuild do
sh('rm -rf sig/generated')
Rake::Task['rbs:build'].execute
end
end
listen gem is 何
ここで唐突に出てきた listen gem は Guard というツールの内部で使われている、ファイル差分検出用の実装。
Guard は「ファイルが変更したときに特定のツール (Bundler, RuboCop, RSpec 等) を呼び出す」ことが出来るツール。
Bundler, RuboCop, RSpec 等のツールを自動で使うなら Guard を使うとよいが、自前でちょっとした watch を行いたい場合は listen gem を直接使うと良いかも。
require 'listen'
listener = Listen.to(*DIRS_TO_WATCH, only: FILE_PATTERN_REGEXP) do |modified, added, removed|
# modified, added, removed はファイル名の配列で、変更された、追加された、削除されたファイル名をそれぞれ表す。
end
Rails でも、直接の依存ではないものの、 ActiveSupport::EventedFileUpdateChecker
を利用する際に必要になる。 (reloader 用のファイル変更の検知機構の1種。)
なので、各プロジェクトの依存 gem としてもしかすると入ってるかも。