Help us understand the problem. What is going on with this article?

Ruby | Guard gem を利用してファイルの変更を検出し、任意のタスクを自動実行する

More than 5 years have passed since last update.

Ruby | Guard gem を利用してファイルの変更を検出し、任意のタスクを自動実行する

概要

Guard gem を利用してファイルの変更を検出し、任意のタスクを自動実行する。
今回はファイル変更時に RSpec を実行してみます。

インストール

  • guard の RSpec Plugin も一緒にインストールします
$ gem install guard --no-ri --no-doc
$ gem install guard-rspec --no-ri --no-doc

設定ファイル(Guardfile)の生成

RSpec対応のひな形を生成します。

$ guard init rspec

下記のようなテンプレートが生成されます

Guardfile
guard :rspec 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|\.slim)$})          { |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|slim)$})     { |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' }
end

設定ファイルの編集

下記のように編集します。

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

guardを起動します

$ guard start

プログラムのひな型を生成します

自作 gem の rspec_piccolo を利用します。
rspec_piccoloはプロダクトコードとテストコードのひな形を生成する CLI ツールです。

詳しくは
https://github.com/tbpgr/rspec_piccolo
を参照。

piccolo e Hoge hoge hoge -p

これで、以下のファイルが生成されます。

lib/hoge.rb
# encoding: utf-8


class Hoge
  def hoge
    # TODO: implement your code
  end
end
spec/hoge_spec.rb
# encoding: utf-8
require "spec_helper"
require "hoge"

describe Hoge do

  context :hoge do
    cases = [
      {
        case_no: 1,
        case_title: "case_title",
        expected: "expected",
      },
    ]

    cases.each do |c|
      it "|case_no=#{c[:case_no]}|case_title=#{c[:case_title]}" do
        begin
          case_before c

          # -- given --
          hoge = Hoge.new

          # -- when --
          # TODO: implement execute code
          # actual = hoge.hoge

          # -- then --
          # TODO: implement assertion code
          # expect(actual).to eq(c[:expected])
        ensure
          case_after c
        end
      end

      def case_before(c)
        # implement each case before
      end

      def case_after(c)
        # implement each case after
      end
    end
  end
end

自動生成されたファイルを検知して、guardが実行されます

[1] guard(main)>

22:45:17 - INFO - Running: spec/hoge_spec.rb
Run options: include {:focus=>true}

All examples were filtered out; ignoring {:focus=>true}
.

Finished in 0 seconds
1 example, 0 failures

テストを実装後、プロダクトコードを保存したguardの実行結果を確認します

spec/hoge_spec.rb
# encoding: utf-8
require "spec_helper"
require "hoge"

describe Hoge do

  context :hoge do
    cases = [
      {
        case_no: 1,
        case_title: "valid case",
        expected: "hoge",
      },
    ]

    cases.each do |c|
      it "|case_no=#{c[:case_no]}|case_title=#{c[:case_title]}" do
        begin
          case_before c

          # -- given --
          hoge = Hoge.new

          # -- when --
          actual = hoge.hoge

          # -- then --
          expect(actual).to eq(c[:expected])
        ensure
          case_after c
        end
      end

      def case_before(c)
        # implement each case before
      end

      def case_after(c)
        # implement each case after
      end
    end
  end
end
[1] guard(main)>

22:47:05 - INFO - Running: spec/hoge_spec.rb
Run options: include {:focus=>true}

All examples were filtered out; ignoring {:focus=>true}
F

Failures:

  1) Hoge hoge |case_no=1|case_title=valid case
     Failure/Error: expect(actual).to eq(c[:expected])

       expected: "hoge"
            got: "# TODO: implement your code"

       (compared using ==)
     # ./spec/hoge_spec.rb:28:in `block (4 levels) in <top (required)>'

Finished in 0.001 seconds
1 example, 1 failure

Failed examples:

rspec ./spec/hoge_spec.rb:17 # Hoge hoge |case_no=1|case_title=valid case

プロダクトコードを実行して、テストをパスするようにしてファイルを保存します。

テストが成功することを確認できました

lib/hoge.rb
# encoding: utf-8


class Hoge
  def hoge
    'hoge'
  end
end
[1] guard(main)>

22:48:46 - INFO - Running: ./spec/hoge_spec.rb:17
Run options: include {:locations=>{"./spec/hoge_spec.rb"=>[17]}}
.

Finished in 0.001 seconds
1 example, 0 failures
Run options: include {:locations=>{"./spec/hoge_spec.rb"=>[17]}}
.

Finished in 0.001 seconds
1 example, 0 failures

参照

https://github.com/guard/guard
http://rubygems.org/gems/guard

Guard まとめ記事

http://qiita.com/tbpgr/items/7905535aa0a1d9131688

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away