Guard::Yield
A Guard pseudo-plugin to conveniently run any Ruby code - straight from your Guardfile (without writing your own plugin).
Installation
in your Gemfile:
group :development do
gem 'guard-yield'
end
Install with:
$ bundle install
Or install it yourself as:
$ gem install guard-yield
Usage
Add snippets to your Guardfile
with:
$ bundle exec guard init yield
Then, edit/remove them and run:
$ bundle exec guard
Useful example
Automatically building Docker images from a Dockerfile in Guard:
run_docker = proc do
image = "my_image"
system("docker build -t #{image} .") || throw(:task_has_failed)
end
guard :yield, { :run_on_modifications => run_docker } do
watch(/^Dockerfile$/)
end
(You could use the Docker API, require 'docker'
, etc. but this is less work and nice output, and the task doesn't get fired if it fails).
Another example
Show a list of md5sums whenever these files change
md5_summer = proc { |_, _, files| puts `md5sum #{files * ' '}` }
guard :yield, run_on_modifications: md5_summer do
watch('foo.rb')
watch('bar.rb')
watch('baz.rb')
end
Yes, you don't need to resort to hax with the watch()
block or creating
inline Guard plugins in your Guardfile. Especially for local one-shot pieces of
code like this.
Tips
Aside from supporting all the methods for Guard::Plugin:
:start
:stop
:run_all
:reload
:run_on_additions
:run_on_modifications
:run_on_removals
:run_on_changes
there's a special :object
option, that allows you to pass any object you like
to all the methods.
(Just check the logger example in the Guardfile).
This means you can conveniently use any Ruby library inside your Guardfile - without writing a Guard plugin as a wrapper for it.
Also, remember to use Guard's throw(:task_has_failed)
to flag an error
(otherwise Guard will disable your guard), e.g. :
my_syntax_checker = proc do |_, _, changes|
changes.each do |file|
system("ruby -c #{file}") || throw(:task_has_failed) # IMPORTANT!
end
end
guard :yield, run_on_modifications: &my_syntax_checker do
watch('foo.rb')
watch('bar.rb')
end
FAQ
"Why not use the watch() block for running code?"
- That's not what it's for (you need the
return nil
hack at least) - You don't have access to the guard object (even if it's your own)
- You can't pass data to the block (you just have the file)
- The dsl has it's own namespace - guard-yield side-steps that
- This cleanly separates rules (which can get complex) from behavior
- It really is just for substituting one change for another (not for code)
Here's an example anyway (NOT RECOMMENDED!):
# nil to prevent plugin for doing anything itself
watch("foo.*") { |m| `cp #{m} #{m}.backup`; nil }
"Why not use an inline Guard plugin inside the Guardfile?"
Usually it's the Object-Oriented way to do things, and it's likely easier to extract into a gem.
But if you don't want to create a full-blown gem, or you want the logic to be local, verbose and concise ... guard-yield will help.
And as above - guard-yield allows you to prototype an interface to any Ruby library and use that directly in your Guardfile - and often with less code, classes and methods to get the job done.
"Why not just create a gem/lib for every task like that?"
One reason is - you may quickly end up with too many gems to maintain (for no reason), while those gems will just be a thin, minimal front-end to a complex Ruby library.
Basically it all boils down to how many options you want your guard plugin to handle - and how complex handling them is.
Not every use case can be extracted into a nice generic gem useful for many people - that's why I created this gem.
Have fun!
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/guard-yield.
License
The gem is available as open source under the terms of the MIT License.