At Grand Rounds we write a lot of scripts to automate our development process and link together the services we use. For example, we have a tool that automatically names git branches based on their corresponding stories in Pivotal Tracker. We also have scripts to infer what features are included in a release based on git commit logs.
Script dependencies are annoying
Since we’re primarily a Ruby shop, it’s often convenient to use Ruby for these scripts. Usually they start out as a simple executable file with
#!/usr/bin/env ruby at the top, followed by a few
require statements. Put the file somewhere in your
$PATH and it’s ready to go.
When you start requiring gems for API clients, argument parsing, and more, though, dependency management becomes a problem. Simply requiring everything you need at the top of the file leaves users with the chore of manually installing a bunch of gems and keeping them up to date.
Bundler to the rescue
That’s the kind of problem that RubyGems and Bundler were built to solve. If you write Rails applications, you’re probably familiar with the most common use case for Bundler: a project will include a
Gemfile where gem dependencies are laid out, and Bundler provides commands that make it easy to install and maintain them. Fortunately, it’s also versatile enough to help maintain your scripts’ dependencies by packaging them as gems. The built-in generator makes the process easy.
What follows is a quick & dirty guide to turning a standalone script into a gem. There’s a lot more to gems than I’ll cover here, but if you just want a way to get a script’s dependencies under control, this gets the job done.
Here’s a script I wrote that uses the Tracker API to list the ten biggest stories in a project.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
Generating a gem
To turn this into a gem, I’ll use the
bundle gem command to generate a skeleton for the project.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Bundler just did most of the work for me, and it finished by opening
bigstories.gemspec in my editor so that I can fill in the gem specification. I’ll fill in the lines marked with
TODO, add my dependencies, and save the file.
1 2 3 4 5 6 7 8
Since I added the
--bin flag to
bundler gem, Bundler automatically created
exe/bigstories for me. I’ll copy & paste my Tracker script into it.
The gem is ready to install, and all I had to do was
- fill in the gemspec, and
- add my script to
To install the gem locally, I’ll run
1 2 3
That’s it. My
bigstories gem is installed and ready to go:
1 2 3 4 5 6 7 8 9 10 11