読者です 読者をやめる 読者になる 読者になる

もた日記

くだらないことを真面目にやる

Railsメモ(23) : GuardでRuboCopを自動実行する

Ruby on Rails

RuboCopで静的コード解析ができるようになったが、手動で実行するのは面倒だし忘れるのでGuardで自動実行する方法を試してみる。

Guardのインストール


github.com

Guardはファイルやディレクトリの変更を監視して、さまざまな処理を自動化するgemで、プラグインを追加して利用する。
まず、Gemfileに下記行を追加してbundle installする。

group :development do
  gem 'guard'
end

bundle execなしでコマンドを実行するために下記コマンドを実行してbin/guard, bin/_guard-coreを生成する(加えて、direnvでbin以下のコマンドを実行するように設定しておく)。

$ bundle binstub guard
$ ls bin
_guard-core  bundle  guard  rails  rake  setup  spring

下記コマンドを実行して設定ファイルのGuardfileを生成する。

$ guard init
23:00:13 - INFO - Writing new Guardfile to /home/vagrant/rails/billboard/Guardfile

設定ファイルの内容は以下のようなものでプラグインを追加すると、このファイルに設定が追記されていく。

$ cat Guardfile
# A sample Guardfile
# More info at https://github.com/guard/guard#readme

## Uncomment and set this to only include directories you want to watch
# directories %w(app lib config test spec features) \
#  .select{|d| Dir.exists?(d) ? d : UI.warning("Directory #{d} does not exist")}

## Note: if you are using the `directories` clause above and you are not
## watching the project directory ('.'), then you will want to move
## the Guardfile to a watched dir and symlink it back, e.g.
#
#  $ mkdir config
#  $ mv Guardfile config/
#  $ ln -s config/Guardfile .
#
# and, you'll have to watch "config/Guardfile" instead of "Guardfile"

これで設定は完了したのでGuardを起動する。
プラグインがないためERRORとなっているがGuardのインストールは完了。

$ guard
23:00:22 - ERROR - No plugins found in Guardfile, please add at least one.
23:00:22 - INFO - Guard is now watching at '/home/vagrant/rails/billboard'
[1] guard(main)>


guard-rubocopのインストール


github.com

RuboCopを自動実行するためにGuardのプラグインであるguard-rubocopをインストールする。
Gemfileに下記行を追加してbundle installする。

group :development do
  gem 'guard-rubocop'
end

Guardfileに設定を追加するために下記コマンドを実行する。

$ guard init rubocop
23:07:11 - INFO - rubocop guard added to Guardfile, feel free to edit it

Guardfileを見ると下記内容が追加されていることが確認できる。watchで監視するファイルを設定している。

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


guard-rubocopの使い方


これで設定は完了なのでGuardを起動してみる。デフォルトではGuard起動時にもrubocopを実行するようになっているため静的コード解析が実行される。どうやらGuardfileに自動生成されたコードに問題があるようだ。
ということで、このコードを修正したらrubocopが自動実行されるか確認してみるが、Guardは終了せずに起動したままにしておく。

$ guard
23:10:02 - INFO - Inspecting Ruby code style of all files
Inspecting 36 files
...C................................

Offenses:

Guardfile:19:9: C: Use // around regular expression.
  watch(%r{.+\.rb$})
        ^^^^^^^^^^^

36 files inspected, 1 offense detected

23:10:04 - INFO - Guard is now watching at '/home/vagrant/rails/billboard'

コーディングスタイルによると/を使用する正規表現のみ%rを使用すべきということなので、エディタで以下のように変更して保存する。

  # watch(%r{.+\.rb$})
  watch(/.+\.rb$/)

保存が完了するとGuardが変更を検知してrubocopを自動実行してくれる(違反の数が0になった)。

[1] guard(main)> 23:11:27 - WARN - Guardfile changed -- _guard-core will exit.
> [#]

23:11:27 - INFO - Bye bye...
23:11:28 - INFO - Inspecting Ruby code style of all files
Inspecting 36 files
....................................

36 files inspected, no offenses detected
23:11:31 - INFO - Guard is now watching at '/home/vagrant/rails/billboard'
[1] guard(main)>


guard-rubocopの設定


設定可能なオプションとしては以下の項目がある。

all_on_start: true     # Check all files at Guard startup.
                       #   default: true
cli: '--rails'         # Pass arbitrary RuboCop CLI arguments.
                       # An array or string is acceptable.
                       #   default: nil
hide_stdout: false      # Do not display console output (in case outputting to file).
                       #   default: false
keep_failed: true      # Keep failed files until they pass.
                       #   default: true
notification: :failed  # Display Growl notification after each run.
                       #   true    - Always notify
                       #   false   - Never notify
                       #   :failed - Notify only when failed
                       #   default: :failed

Guard起動時にrubocopを実行したくないのでGuardfileを以下のように変更して、Guard起動時にrubocopを実行しないようにした。

 # guard :rubocop do
 guard :rubocop, all_on_start: false do


guard-rubocopの結果を通知させる


自動実行されるのは便利だが結果画面をわざわざ確認しにいくのは大変なので、その場合は通知機能を使用するとよい。通知の方法としては下記リンクにいろいろと書いてあるが、普段tmuxを使用しているので、tmuxのステータスラインに表示する方法を試してみる。

設定可能な内容は下記項目であるが、

# Guardfile
notification :tmux,
  display_message: true,
  timeout: 5, # in seconds
  default_message_format: '%s >> %s',
  # the first %s will show the title, the second the message
  # Alternately you can also configure *success_message_format*,
  # *pending_message_format*, *failed_message_format*
  line_separator: ' > ', # since we are single line we need a separator
  color_location: 'status-left-bg', # to customize which tmux element will change color

  # Other options:
  default_message_color: 'black',
  success: 'colour150',
  failure: 'colour174',
  pending: 'colour179',

  # Notify on all tmux clients
  display_on_all_clients: false

色が変になったり、デフォルトの設定と変わらない項目もあったので下記内容をGuardfileに追記した。

notification :tmux,
  display_message: true,
  default_message_format: '%s >> %s',
  line_separator: ' > ',
  color_location: 'window-status'

RuboCopの結果に違反があると図のようにtmuxのステータスラインに表示されるようになる。なお、違反がない場合は何も変化はない。

f:id:wonder-wall:20150818231939p:plain

パーフェクト Ruby on Rails

パーフェクト Ruby on Rails