In Progress
Unit 1, Lesson 1
In Progress

Rerun

Video transcript & code

In developing Ruby applications, there is a constant cycle of editing the code, then running the code, then editing again, and so on. "Running" the code can take a few different forms: it may mean starting and re-starting an application in order to manually test it. Or it may mean running a suite of automated tests.

Because this cycle is so ubiquitous, many strategies and thousands of lines of code have been devised and written to automate the process of re-loading or re-starting code after files have been changed.

But sometimes all we need is a simple and bulletproof approach. Let's say we're working on a Sinatra app. We're a half-hour in, and we're already fed up with having to manually restart our development server every time we change a line of code.

require "sinatra"

get "/" do
  "Hello world"
end

All we want to do is monitor the current directory for when a Ruby file changes, and then restart the whole application. We're not worried about partial code reloading or fancy dependency tracking or anything like that.

This is a purpose that the "rerun" gem is perfectly suited for. To use it, we enter rerun, followed by the command we want to restart.

rerun ruby app.rb

When we make a change to a Ruby file in the same directory and then save it, we can watch as rerun terminates the process and then re-runs it.

 $ rerun ruby app.rb

16:01:27 [rerun] 320-rerun launched
== Sinatra (v1.4.6) has taken the stage on 4567 for development with backup from Thin
Thin web server (v1.6.3 codename Protein Powder)
Maximum connections set to 1024
Listening on localhost:4567, CTRL+C to stop
16:01:29 [rerun] Watching . for **/*.{rb,js,coffee,css,scss,sass,erb,html,haml,ru,yml,slim,md} using Linux adapter
16:01:45 [rerun] Change detected: 1 modified
16:01:45 [rerun] Sending signal TERM to 14541
Stopping ...
== Sinatra has ended his set (crowd applauds)

16:01:45 [rerun] 320-rerun restarted
== Sinatra (v1.4.6) has taken the stage on 4567 for development with backup from Thin
Thin web server (v1.6.3 codename Protein Powder)
Maximum connections set to 1024
Listening on localhost:4567, CTRL+C to stop

Actually, in the case where the command we want to keep re-starting is just a Ruby script, we can even leave off the ruby part. rerun is a Ruby-oriented tool, so if it sees a .rb file it guesses that that's what we want to do.

$ rerun app.rb

How does it know where to look for files to watch? Well, by default, it just looks in whatever directory it was started in. We can customize this by using the -d option with a comma-separated list of directories.

$ rerun -d app,lib

rerun doesn't watch every possible file. When we look at its built-in help, we can see the file glob pattern it normally uses. The **/* part means that it will track not just files in the current directory, but also files in any subdirectories, no matter how deep. The rest of the pattern is a list of file extensions commonly found in Ruby projects. If we ever need to change what files it tracks, we can use this -p option to do it.

 $ rerun --help
...
  -p, --pattern pattern    file glob to watch, default = "**/*.{rb,js,coffee,css,scss,sass,erb,html,haml,ru,yml,slim,md}"
...

Speaking of options, we may need to re-run a command which takes arguments of its own. In this scenario, we can add a -- between the rerun options and the command to be restarted. This lets rerun know unambiguously where its own options stop and the command begins. For instance, in this example, the Sinatra -p flag clashes with the rerun -p flag, but the double dash clarifies that it belongs to the subcommand.

$ rerun -- ruby app.rb -p 4000

The two most common uses for a tool like this are 1. re-starting an application; and 2. running tests. We've already seen how re-run can be used for the first purpose. In order to use re-run to run a test suite every time a file is saved, we can supply the -x flag. This flag tells rerun to expect the command to run and then exit, instead of expecting it to continue indefinitely. Now every time we change a file, rerun re-runs the application tests.

rerun -x rspec

When run in this mode, you'll see that some interactive commands become available. There are simple one-key commands for re-running the test, pausing them, clearing the screen, and more.

Re-run has several other options, but the list is not overwhelmingly long, so I recommend looking them over to get a feel for what else the tool can do.

 $ rerun --help
Usage: rerun [options] [--] cmd

Launches an app, and restarts it when the filesystem changes.
See http://github.com/alexch/rerun for more info.
Version: 0.10.0

Options:
  -d, --dir dir            directory to watch, default = "["."]".  Specify multiple paths with ',' or separate '-d dir' option pairs.
  -p, --pattern pattern    file glob to watch, default = "**/*.{rb,js,coffee,css,scss,sass,erb,html,haml,ru,yml,slim,md}"
  -i, --ignore pattern     file glob to ignore (can be set many times). To ignore a directory, you must append '/*' e.g. --ignore 'coverage/*'
  -s, --signal signal      terminate process using this signal, default = "TERM"
  -c, --clear              clear screen before each run
  -x, --exit               expect the program to exit. With this option, rerun checks the return value; without it, rerun checks that the process is running.
  -b, --background         disable on-the-fly commands, allowing the process to be backgrounded
  -n, --name name          name of app used in logs and notifications, default = "320-rerun"
      --no-growl           don't use growl
  -h, --help, --usage      show this message
      --version            show version

On top of --pattern and --ignore, we ignore any changes to files and dirs starting with a dot.

You may have noticed that, unlike other tools in this category, I have yet to mention a configuration file. and that's deliberate. The philosophy behind rerun is that it's simple enough that you can remember the options you need and just specify them on the command like, without having to resort to a configuration file. At worst, you can always refresh your memory with the --help flag; its output contains everything you need to know.

I'm not going to say that rerun should replace all other tools for restarting or re-loading code. But what's great about it is that unlike other solutions, you don't need to resort to documentation to remember hope to configure it. Most of the time, you can just stick rerun in front of the command you're tired of re-entering, and forget about it.

And that's it for today. Happy hacking!

Responses