I'm trying to set up a working ruby project with guard-rspec
.
I've mixed together the general method of a tutsplus tutorial with some new syntax as described in the RSpec videos and another post. The project can be found in the stack-overflow-question
branch on github.
I'm also trying to practice namespacing as described in Programming Ruby 1.9. So eventually I'd like to have example.rb
in my lib/example/
directory.
There's 4 questions I have about my project:
- What do I need to put in my
Guardfile
to watch specific directories in my project for changes? I've several different ways which can be seen in my Guardfile
as comments labelled like:
# Watch Specific Directory Attempt X
What is the difference between uncommenting lines 8 and 9 in my Guardfile
(bellow Uncomment and set this to only include directories you want to watch
) and adding "named group captures" like watch(%r{^lib/(?<path>.+)\.rb$}) { |m| "spec/lib/#{m[:path]}_spec.rb" }
as described here
Where do I need to put the --clear
option to make it persistent? I know I can run it with my binstub like bin/guard --clear
and I've tried putting that in my Guardfile
however it didn't work.
Are there any glaring convention, syntax, or clarity mistakes that you see in my project? I feel like I'm duck taping this whole thing together and I'd appreciate some guidance in piecing this thing together in a sensible way.
I'll answer the question in the title and cover the "sub-questions" as I go.
The best way to set up a project (as of now) is to use bundle exec guard --init rspec
. This should give reasonable defaults to start work immediately. It's not perfect, but there is a lot of work planed to improve things, so do ask questions on GitHub instead (makes more sense).
Guard has to maintain backward compatibility, so there are some "non-intuitive" things for now and skimming through all the docs first (and wiki) is a good investment to quickly know what's available and where. Asking when confused or in doubt is also a good idea (one issue per question is best).
Guard uses a DSL to simplify setting up listeners. This is a bit non-intuitive and clunky at times, but it does help organize actions into groups, which can help maintain complex workflows. The DSL's command for e.g. clearing the terminal automatically is: (clearing: on
). (This answers question 3).
There are all kinds of uses and scenarios, so Guard tries hard to make everyone happy and on every platform too. Guard uses Listen, which watches directories recursively (due to restrictions on OSX mostly). This usually isn't a problem, but for huge directions on OSX this can be very, very slow. That's why Guard lets you select which top directories to watch (like 'lib', 'app', etc.). Watching the whole project directory is very convenient, so that is still the default. More info on this is at the Listen project. So by default all directories (:directories
statement) are "physically watched" (take up operating resources), though in Guard you only configure which changes you want to respond to (which is what watch
statements do).
The words chosen are a bit misleading at times. E.g. watch
in the DSL actually means: "out of all the changes happening, select changes matching ...". The block passed to watch
is given the results of the match. That block should return a list of files for the current guard plugin to run. So "watch" probably is more misleading than helpful. "match" would probably be a better choice and it might replace "watch" in the future.
The guard-rspec project runs RSpec on changed files. You can see the exact RSpec commands if you run guard with the debugging option on, e.g. bundle exec guard -d
. To simplify setup, Guard::RSpec uses a DSL that should work out-of-the-box if your project follows a given setup. E.g. dsl.watch_spec_files_for(ruby.lib_files)
is defined here: so it pretty much already should do what you want if you put all your tested source files in lib
. For other folders, you can add your own. E.g. Rails projects typically have sources also in an app
directory, so in the default Guard::RSpec template there's an statement: dsl.watch_spec_files_for(rails.app_files)
with the pattern defined as: rails.app_files = %r{^app/(.+)\.rb$}
If you have a typical case that isn't covered, open an issue in that project. (covers question 2).
Everything looks fine in the example project and suggestions are mostly based on taste or preference. E.g.
- Instead of
let (:greeter) { Example::RSpecGreeter.new }
, I'd use RSpec's implicit subject (but some may argue that it's less explicit and less readable)
- if you're testing
Example::RSpecGreeter
, I'd recommend putting that class in a separate file and including it instead (require 'example/rspec_greeter'
)
- you might add RubCop/Guard::RuboCop for detecting convention issues (covers 4th question)
- you might want to check out Guard's own Guardfile used to test itself for a more "real-life" setup without the documentation clutter.
- for best results I think it's best to copy a whole existing project and rename the parts you want to change. Usually there are many hours spent still fine-tuning things like alternate RSpec configs for Travis, special gem release tasks, certain workarounds and conveniences, etc.