Rails appのコードを変更したときに、Guardに自動でRuboCop、RSpecを実行してもらう

Guardとは

Guardはファイルに変更があったときに、タスクを走らせてくれるgemで、コードを変更したときに、静的なコードチェックをしてくれるRuboCopやRSpecで書かれたテストを実行させることができる。RuboCopやテストコードを随時走らせてコーディングしていくと、問題を即座に把握できるので、プルリク前にあわててテストコードを走らせて修正....というハメに陥らなくて済む。

導入方法

Gemfile

Gemfileに以下のgemを追加。RSpec、RuboCopの導入はすでに終わっているものとする。

group :development do
  ...
  gem 'guard-rspec'
  gem 'guard-rubocop'
  ...
end

インストールも忘れずに。

$ bundle install

Guardfile

Guardの設定ファイルを作成する必要がある。以下のコマンドで生成できる。

$ bundle exec guard init rspec
$ bundle exec guard init rubocop

このようなGuardfileになる。このファイルを変更することで、監視対象とするファイルを変更したり、rspecが落ちた時の RuboCopの実行をスキップしたりできる。

guard :rubocop, cli: '--rails' do
  watch(/.+\.rb$/)
  watch(%r{(?:.+/)?\.rubocop\.yml$}) { |m| File.dirname(m[0]) }
end

guard :rspec, cmd: 'bundle exec rspec' do
  require 'guard/rspec/dsl'
  dsl = Guard::RSpec::Dsl.new(self)

  # RSpec files
  rspec = dsl.rspec
  watch(rspec.spec_helper) { rspec.spec_dir }
  watch(rspec.spec_support) { rspec.spec_dir }
  watch(rspec.spec_files)

  # Ruby files
  ruby = dsl.ruby
  dsl.watch_spec_files_for(ruby.lib_files)

  # Rails files
  rails = dsl.rails(view_extensions: %w(erb haml slim))
  dsl.watch_spec_files_for(rails.app_files)
  dsl.watch_spec_files_for(rails.views)

  watch(rails.controllers) do |m|
    [
      rspec.spec.call("routing/#{m[1]}_routing"),
      rspec.spec.call("controllers/#{m[1]}_controller"),
      rspec.spec.call("acceptance/#{m[1]}")
    ]
  end

  watch(%r{^app/api/(.+)\.rb$}) { |m| "spec/api/#{m[1]}_spec.rb" }

  # Rails config changes
  watch(rails.spec_helper)     { rspec.spec_dir }
  watch(rails.routes)          { "#{rspec.spec_dir}/routing" }
  watch(rails.app_controller)  { "#{rspec.spec_dir}/controllers" }

  # Turnip features and steps
  watch(%r{^spec/features/(.+)\.feature$})
  watch(%r{^spec/steps/(.+)_steps\.rb$}) do |m|
    Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/features'
  end
end

rspecが落ちた時に RuboCopの実行をスキップしたい場合は、 以下のようにGuardfileを変更するとよい。

# This group allows to skip running RuboCop when RSpec failed.
group :red_green_refactor, halt_on_fail: true do
  guard :rspec do
    # ...
  end

  guard :rubocop do
    # ...
  end
end

Guardを実行してファイルを監視

実行するだけ。

$ bundle exec guard

おわりに

Guardを使って開発しているとプルリクする前にあわててテストを実行しなくてよくて便利。 快適railsライフを送りましょう。