Minimum viable guard

Published
7 September 2016
Tagged

Guard is a cool ruby library for automatically performing tasks every time a file changes. But if you're not sure what to expect, it can be hard to set up. Here's the quickest possible setup for Guard.

Use case

In this case, I'm making a quick website prototype in haml. I want to make sure that, whenever I modify one of my haml files, ruby immediately produces the equivalent html file for me in the same directory.

Installation

To set up guard, first you must install it:

gem install guard

Once that's all done, you're ready to go!

Setup

Navigate to the root directory for your project and create a new file, named Guardfile. This is where you tell guard what to do.

Guard runs using a series of plugins, which must be subclasses of Guard::Plugin. There's a few methods you can override for your plugin, but the most important are start and run_on_modifications:

  • start runs when the plugin is loaded. It's useful for informing you that the plugin successfully loaded, or for setting up any initial variables you need set up.
  • run_on_modifications runs whenever a watched file is modified. We'll talk about watched files in a bit - what you need to know is that guard will pass this method an array of paths, corresponding to the modified files.

Let's have a look at a sample plugin for turning haml files into html files:

# I need this to run haml
require "haml"

class Guard::Hamliser < Guard::Plugin 
  def start
    puts "Starting Hamliser"
  end

  def run_on_modifications(paths)
    paths.each do |haml_file|
      html_file = haml_file.gsub(".haml", ".html")
      # Render the HAML file into the HTML file
      File.open(html_file, "w"){ |io| io.puts Haml::Engine.new(File.read(haml_file)).render }
      puts "Rendered #{haml_file} to #{html_file}"
    end
  end
end

You don't need to print a status message for every modification, but I find it handy.

Watching files

The last thing you need to do is tell guard what to watch. You do this with the guard method, which takes one argument (the Plugin subclass to run, in string form) and a block. The block tells guard which files to watch through a series of different commands, but the most basic is the watch method:

guard("hamliser") do
  watch %r|.*\.haml$|
end

watch takes a string or regex argument, and matches the path of each changes file against this. You can run watch multiple times within the same block: as one of the watch arguments matches, the path will be passed to run_on_modifications. Here, I specify that I only care about files ending in .haml.

Gluing it together and making it go

Now all that remains is to add the guard syntax to the end of my guard file:

require "haml"

class Guard::Hamliser < Guard::Plugin 
  def start
    puts "Starting Hamliser"
  end

  def run_on_modifications(paths)
    paths.each do |haml_file|
      html_file = haml_file.gsub(".haml", ".html")
      # Render the HAML file into the HTML file
      File.open(html_file, "w"){ |io| io.puts Haml::Engine.new(File.read(haml_file)).render }
      puts "Rendered #{haml_file} to #{html_file}"
    end
  end
end

guard("hamliser"){ watch %r|.*\.haml$| }

To run this from the command line, navigate to your root folder and run the guard command. You're all ready to go!