CakePHP に Guard を導入

Guard とは何か?

Guard とは、ruby のライブラリ。ファイルの変更を監視して、変更を検知したら指定の処理を実行する。この性質を利用して、ファイルが変更されたらテストを実行するということに用いられる。
Guard のソースコード

前準備

  • CakePHP のプロジェクト、テストがあるやつ。
  • PHPUnit のインストール
  • ruby のインストール

上記が済んでいる前提ですすめる。

guard のインストール

今回は Gemfile からインストールする。もし bundle をインストールしてなければ

gem install bundle --no-ri --no-rdoc

でインストールしておく。
CakePHP のプロジェクトの app 直下に Gemfile を作成しておく

$ cd {$CakePHP_Project}/app
$ vim Gemfile

# Gemfile

source 'https://rubygems.org'

group :development, :test do
  gem 'guard-shell'
  gem 'ruby_gntp' # 通知用のライブラリ. 監視だけならいらない
end

app 直下で下記を実行する

$ bundle install

guard の設定

Gemfile と同じ階層に Guardfile を設置する。

# Guardfile
guard :shell do
  watch(%r{Controller/(.+)\.php}) {|m| `Console/cake test app AllController --some-option`}
  watch(%r{Model/(.+)\.php}) {|m| `Console/cake test app AllModel`}
end

watch 〜 の行が監視するファイルと、変更されたら実行するシェルスクリプトになっている。このへんは各自のプロジェクトによって変更する。Plugin をテストする場合は `Console/cake test Hoge AllPlugin` のようなシェルを実行するとよい。

監視を開始する

app 直下で、下記のコマンドを実行する

$ bundle exec guard

変更を通知する

ホストマシンで実行してるなら、このへんにあるライブラリを利用すればよい。
vagrant などで VM 上で監視している場合は、フックが必要。なぜか GNTP ではゲスト(Ubuntu13.10)からホスト(Windows7)への通知が notification: ではうまくいかなかった。適当に --log-tap オプションを追加して、テスト結果を tmp/tests フォルダ以下に出すようにして、そのファイルを監視して自力で通知した。なんかいい方法あったら教えてください。

# Guardfile

guard :shell do
  watch(%r{Controller/(.+)\.php}) {|m| `Console/cake test app AllController --log-tap tmp/tests/controller.tap`}
  watch(%r{tmp/tests/(.+)\.tap}) {|m| `ruby notify.rb`}
end

そして通知用のスクリプトを Guardfile と同じ階層においた
# notify.rb

# coding: utf-8                                                                                                    
require 'ruby_gntp' #growlを呼ぶためのgem                                                                          
                                                                                                                   
f = open("tmp/tests/controller.tap")                                                                                  
lastlog = f.read                                                                                                   
f.close                                                                                                            
                                                                                                                   
GNTP.notify({                                                                                                      
    :app_name => "growl",
    :title    => "Notice",
    :text     => tap,
    :host     => "192.168.56.1",
    :passwd   => "pass"
})    

それから、Windows にも growl があるっぽいので下記を参考に growl をインストールした。
Ubuntu ServerのGuardからGrowl for Windowsにネットワーク経由で通知する | | Scimpr Blog

Error が起きる場合

下記を参考にして guard の 2.x 系をアンインストールする
【Laravel】ERROR - Could not load 'guard/phpunit' or find class Guard::Phpunitが出た時の対処法 - ikemonn's blog

$ gem list guard
guard (2.5.1, 1.8.3)
guard-phpunit (0.1.4)
guard-shell (0.6.1)
$ gem uninstall guard -v='2.5.1'