Railsチュートリアル「3.6.2Guardによるテストの自動化」でguard init rspecが失敗する場合の対処法

          • -

(2015/1/9追記)
本件、twitterで呟いたらRailsチュートリアルの中の人(@yaslubさん)が気づいて早速チュートリアル側の記載を修正して下さいましたので、現時点でチュートリアルどおりにやれば本事象は発生しません。仕事が早い。

          • -

Railsチュートリアルやってて、「3.6.2Guardによるテストの自動化」のところがエラー出てうまくいかなくてちょっとハマったので対処法を書いておきます。
第3章 ほぼ静的なページの作成 | Rails チュートリアル

現象としては、Gemfileにguard-rspecを追加して

  gem 'guard-rspec', '2.5.0'

bundle installすると

$ bundle install

これは成功するのだけど、次の、guard init rspecするとこんなかんじのエラーが出ます。

$ bundle exec guard init rspec
12:53:38 - INFO - Writing new Guardfile to /Users/minamijoyo/work/ruby/rails_projects/sample_app/Guardfile
12:53:38 - ERROR - Could not load 'guard/rspec' or '~/.guard/templates/rspec' or find class Guard::Rspec

なんかライブラリがロードできていないっぽいです。
結論だけ知りたい人はGemfileで明示的にguardを2.6.1に指定してbundle update guardすれば解決します。

...
group :development, :test do
  gem 'sqlite3', '1.3.8'
  gem 'rspec-rails', '2.13.1'
  gem 'guard', '2.6.1'
  gem 'guard-rspec', '2.5.0'
end
...

guardのバージョンの更新。

$ bundle update guard

ここからデバッグ。試しにirbでロードしてみると

$ irb
2.0.0-p598 :002 > require 'guard/rspec'
LoadError: cannot load such file -- guard/guard
	from /Users/minamijoyo/.rvm/rubies/ruby-2.0.0-p598/lib/ruby/site_ruby/2.0.0/rubygems/core_ext/kernel_require.rb:45:in `require'
	from /Users/minamijoyo/.rvm/rubies/ruby-2.0.0-p598/lib/ruby/site_ruby/2.0.0/rubygems/core_ext/kernel_require.rb:45:in `require'
	from /Users/minamijoyo/.rvm/gems/ruby-2.0.0-p598@railstutorial_rails_4_0/gems/guard-rspec-2.5.0/lib/guard/rspec.rb:2:in `<top (required)>'
	from /Users/minamijoyo/.rvm/rubies/ruby-2.0.0-p598/lib/ruby/site_ruby/2.0.0/rubygems/core_ext/kernel_require.rb:110:in `require'
	from /Users/minamijoyo/.rvm/rubies/ruby-2.0.0-p598/lib/ruby/site_ruby/2.0.0/rubygems/core_ext/kernel_require.rb:110:in `rescue in require'
	from /Users/minamijoyo/.rvm/rubies/ruby-2.0.0-p598/lib/ruby/site_ruby/2.0.0/rubygems/core_ext/kernel_require.rb:35:in `require'
	from (irb):2
	from /Users/minamijoyo/.rvm/rubies/ruby-2.0.0-p598/bin/irb:12:in `<main>'

guard-rspec-2.5.0/lib/guard/rspec.rb:2で読み込んでる

require 'guard/guard'

という箇所が失敗してるっぽい。
依存関係で入ってるgemのバージョンはGemfile.lockというのに書いてるようなのでこれを見るとguardは2.11.1になってる。

railstutorialのソースGithubにあるんじゃね?と思って探したらあった。
GitHub - railstutorial/sample_app_rails_4: The reference implementation of the sample app for the Ruby on Rails Tutorial (Rails 4)
Gemfile.lock見るとguardは2.6.1になってる。
https://github.com/railstutorial/sample_app_rails_4/blob/master/Gemfile.lock

guardのソースもGithubにあったので見に行くと
GitHub - guard/guard: Guard is a command line tool to easily handle events on file system modifications.
現時点の最新2.11.1だとlib/guard/guard.rbないけど、
2.6.1のソースを見てみるとlib/guard/guard.rbがある。
https://github.com/guard/guard/tree/c807e26488aa1092b084703243bf3d7090c82cc1/lib/guard
どうやらビンゴっぽい。

というわけで、Gemfileに明示的にguardを2.6.1に指定してみる。

source 'https://rubygems.org'
ruby '2.0.0'
#ruby-gemset=railstutorial_rails_4_0

gem 'rails', '4.0.5'

group :development, :test do
  gem 'sqlite3', '1.3.8'
  gem 'rspec-rails', '2.13.1'
  gem 'guard', '2.6.1'
  gem 'guard-rspec', '2.5.0'
end

group :test do
  gem 'selenium-webdriver', '2.35.1'
  gem 'capybara', '2.1.0'
end

gem 'sass-rails', '4.0.5'
gem 'uglifier', '2.1.1'
gem 'coffee-rails', '4.0.1'
gem 'jquery-rails', '3.0.4'
gem 'turbolinks', '1.1.1'
gem 'jbuilder', '1.0.2'

group :doc do
  gem 'sdoc', '0.3.20', require: false
end

group :production do
  gem 'pg', '0.15.1'
  gem 'rails_12factor', '0.0.2'
end

(※注:Mac環境ですがgrowlは入れてません。なんか有償っぽいのでMac通知センターに連携するterminal-notifier-guardというのをあとで試して見ようかと思い。。。)

Gemfile.lockを無視して更新するにはupdateしないいけないよう。

$ bundle update guard

再度試してみる。

$ bundle exec guard init rspec
13:08:00 - INFO - rspec guard added to Guardfile, feel free to edit it

ちゃんとロードされてテンプレファイルできたっぽい。

Guadfileに追記する。

# 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 feature)

## Uncomment to clear the screen before every task
# clearing :on

## Guard internally checks for changes in the Guardfile and exits.
## If you want Guard to automatically start up again, run guard in a
## shell loop, e.g.:
##
##  $ while bundle exec guard; do echo "Restarting Guard..."; done
##
## Note: if you are using the `directories` clause above and you are not
## watching the project directory ('.'), the 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"
require 'active_support/inflector'

guard 'rspec', all_after_pass:false do
  watch(%r{^spec/.+_spec\.rb$})
  watch(%r{^lib/(.+)\.rb$})     { |m| "spec/lib/#{m[1]}_spec.rb" }
  watch('spec/spec_helper.rb')  { "spec" }

  # Rails example
  watch(%r{^app/(.+)\.rb$})                           { |m| "spec/#{m[1]}_spec.rb" }
  watch(%r{^app/(.*)(\.erb|\.haml)$})                 { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
  watch(%r{^app/controllers/(.+)_(controller)\.rb$})  { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
  watch(%r{^spec/support/(.+)\.rb$})                  { "spec" }
  watch('config/routes.rb')                           { "spec/routing" }
  watch('app/controllers/application_controller.rb')  { "spec/controllers" }

  # Capybara features specs
  watch(%r{^app/views/(.+)/.*\.(erb|haml)$})          { |m| "spec/features/#{m[1]}_spec.rb" }

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

  # Custom Rails Tutorial specs
  watch(%r{^app/controllers/(.+)_(controller)\.rb$})  do |m|
    ["spec/routing/#{m[1]}_routing_spec.rb",
     "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb",
     "spec/acceptance/#{m[1]}_spec.rb",
     (m[1][/_pages/] ? "spec/requests/#{m[1]}_spec.rb" :
                       "spec/requests/#{m[1].singularize}_pages_spec.rb")]
  end
  watch(%r{^app/views/(.+)/}) do |m|
    (m[1][/_pages/] ? "spec/requests/#{m[1]}_spec.rb" :
                      "spec/requests/#{m[1].singularize}_pages_spec.rb")
  end
  watch(%r{^app/controllers/sessions_controller\.rb$}) do |m|
    "spec/requests/authentication_pages_spec.rb"
  end
end

試しに実行してみる。

$ bundle exec guard
13:18:20 - INFO - Guard is using TerminalTitle to send notifications.
13:18:20 - INFO - Guard::RSpec is running
13:18:20 - INFO - Running all specs
........

Finished in 0.14311 seconds
8 examples, 0 failures


Randomized with seed 28626

13:18:24 - INFO - Guard is now watching at '/Users/minamijoyo/work/ruby/rails_projects/sample_app'
[1] guard(main)>

ちゃんと動いたっぽい。