I'm trying to setup Guard in my Exercism folder, so that all tests are automatically run (using guard-minitest).
The folder structure looks like this:
.
├── exercism
└── ruby
├── bob
│ ├── bob.rb
│ ├── bob_test.rb
├── etl
│ ├── etl.rb
│ ├── etl_test.rb
...
└── binary_search_tree
├── bst.rb
├── binary_search_tree.rb
└── README.md
Due to the unusual folder structure, I made the following configuration in the Guardfile:
# tell Guard to watch all folders under ruby/
all_dirs = Dir.glob('ruby/*')
directories all_dirs
options = {
test_folders: all_dirs,
test_file_patterns: '*_test.rb',
pride: true
}
guard :minitest, options do
watch(%r{^ruby/([^/]+)/([^/]+).rb$})
end
With this setup I expect that all my tests will be run after any edit to a .rb file.
I run guard in debug mode.
All tests run on startup, as expected.
However, when I edit a .rb file the tests are not run again, although Guard outputs this:
20:43:26 - DEBUG - Interactor was stopped or killed
20:43:26 - DEBUG - Hook :run_on_additions_begin executed for Guard::Minitest
20:43:26 - DEBUG - Hook :run_on_additions_end executed for Guard::Minitest
20:43:26 - DEBUG - Start interactor
I tried many variations in the guard configuration, such as:
watch(%r{^ruby/([^/]+)/([^/]+).rb$}) do |m|
Dir.glob("ruby/#{m[1]}/*_test.rb").first
end
(I expect this to only run the test from the folder in which a file was modified.)
Nothing seems to work. I have to go to guard's interactive console and press ENTER to get tests to run.
What am I doing wrong?
After reading Cezary's answer below, I tried some more things, including trying this on other environments.
It turns out it wasn't guard's fault, but probably the environment I was using.
I initially ran everything in a Codio box. I moved the project to other two machines, a Win8 and an Ubuntu 14.04, and it works fine on both using this Guardfile:
all_dirs = Dir.glob('ruby/*')
directories all_dirs
clearing :on
options = {
test_folders: all_dirs,
test_file_patterns: '*_test.rb',
pride: true
}
guard :minitest, options do
watch(%r{^ruby/([^/]+)/([^/]+).rb$}) do |m|
file = Dir.glob("ruby/#{m[1]}/*_test.rb").first
puts " Should test #{file}"
file
end
end
The output of guard -d
is as follows:
On the Codio box (where it doesn't work):
<!-- language: lang-none -->
08:55:09 - DEBUG - Interactor was stopped or killed
Should test ruby/anagram/anagram_test.rb
08:55:09 - DEBUG - Hook :run_on_additions_begin executed for Guard::Minitest
08:55:09 - DEBUG - Hook :run_on_additions_end executed for Guard::Minitest
08:55:09 - DEBUG - Start interactor
[1] guard(main)>
On Win/Ubuntu (where it works fine):
<!-- language: lang-none -->
11:02:10 - DEBUG - Interactor was stopped or killed
Should test ruby/anagram/anagram_test.rb
11:02:10 - DEBUG - Hook :run_on_modifications_begin executed for Guard::Minitest
11:02:10 - INFO - Running: ruby/anagram/anagram_test.rb
Run options: --seed 52507
# Running tests:
..........
Finished tests in 0.001249s, 8006.0205 tests/s, 8006.0205 assertions/s.
10 tests, 10 assertions, 0 failures, 0 errors, 0 skips
11:02:10 - DEBUG - Hook :run_on_modifications_end executed for Guard::Minitest
11:02:10 - DEBUG - Start interactor
[1] guard(main)>
I don't know why on Codio I get run_on_additions
and on the other two I get run_on_modifications
.
Anyway, I guess that's a Codio issue. I tried with and without Manual Save and it's the same.
I'm one of the guys "responsible" for Guard, and based on this, I wrote a walkthrough: Understanding Guard
Here's a list of things to consider:
structure: if you can, put tests in a separate top folder, ideally 'ruby/test' in your example, and the files in 'ruby/lib'. This is closer to the convention and then things like Guard::Minitest
would work out of the box. (Some editors—like Vim and Emacs—allow you to switch between "alternative" files and they will automatically know where to look for tests or implementation files.)
Guard watches directories recursively (and this can't even be turned off right now). For small projects, you can just watch everything by not specifying a directories
option. But, if you have lots of disk activity in your folder and you have large projects, you'll want to select directories. E.g., in your case, it would be: directories ruby
. So `Dir.glob('ruby/*') doesn't make much sense here.
Guard::Minitest options - if you use the structure I described, this shouldn't be necessary. If not, I think having test_folder: %w(ruby)
should be enough. Also, test_file_patterns
shouldn't be necessary, since your files seem to following the defaults/convention (bob_test.rb
and etl_test.rb
), unless you have something really strange as having test suites inside the bob.rb
and etl.rb
files.
Your watch expression doesn't have any block, so it returns the files changed. Unfortunately, when you change an implementation file (like bob.rb
), that file is passed to Guard::Minitest
, which ignore non-test files (probably using the test_file_patterns
option, so since bob.rb
won't match bob_test.rb
, Guard::Minitest will quietly do ... nothing.
Ideally, rename your Guardfile
, update your gems (Guard::Minitest
basically) and run bundle exec guard init minitest
to so what the "current" recommended template is for Guard::Minitest
and try to tweak that instead. You'll see that the default has:
watch(%r{^lib/(.*/)?([^/]+)\.rb$}) { |m| "test/#{m[1]}test_#{m[2]}.rb" }
which shows how to translate changed implementations files into test files (which are the only files Guard::Minitest
cares about).
In your case, you may want:
watch(%r{^ruby/(.*/)?([^/]+)\.rb$}) { |m| "ruby/#{m[1]}/#{m[2]}_test.rb" }
I'd say the regular expressions are horrible, and I'm planning to implement glob pattern support, but this will take a while (lots of critical bug fixes in the pipeline for me).
If this doesn't help, definitely go through the Wiki document above, since there are about 20-50 problems you can have with Guard/Listen, and most are completely outside Guard's/Listen's control.
Since bugs are a priority for me, like most maintainers, we rely on issues reported into GitHub. So we don't usually watch stuff in Stack Overflow (we expect tough issues to be reported in GitHub).
Ok, I've pointed out so many things wrong, and it is time for stuff you did very, very well:
Running Guard
in debug mode. You're awesome for doing that
Showing output regarding the changes. You're awesome for doing that as well (since this shows the Guard::Minitest is getting the changes, but it's ignoring them, likely since you're passing implementation files and not test files).
Submitting such a detailed issue. That's so helpful. Ideally, you shouldn't have gone through all the trouble (or even had the issue in the first place), but by reporting this you're showing us what is wrong with Guard on so many levels. (Often, as developers/maintainers we "get" the internals, so we "know" what's wrong immediately, even though the documentation or messages or debug output says nothing to others, so issues like this help us help others very much).
Thanks again for this. If you ever see other people with issues you can resolve, please do so. If you see obvious bugs or issues in Guard, please open an issue in Guard. If it's in another plugin repository (like Guard::Minitest
), just mention me so that important issues aren't ignored (mention me as @e2
on GitHub).
I do hope to make Guard better. Currently I'm working hard to make it simpler, more intuitive, more flexible and more reliable. The more I can count on people reporting broken stuff, the faster I can move ahead with cool stuff.