This post is very old and contains obsolete information.
Some scripts work well because they are self contained and don’t have a lot of dependancies, like the hosts on your network tracker.
- have more code than fits into a single file
- multiple options and switches
- have an extensive set of dependancies
And on those cases, its better to make a gem and use thor
Hammer of the Gods
Lets figure out how to make some command line tools and package them up so that they can be shared and used by other people. Being able to write a script for one off tasks or simple automation is often a lot easier than building out a full app. There are a lot of libraries and gems out there that make it easy to get information from out there on the web, and they generally require a little glue to make it work.
This article is a walk through in building out a command line utility that will let you pass in a URL that will search hacker news for any mentions. In further postings, we’ll see how to integrate twitter and google analytics searching.
First, building a beautiful gem
Rubygems is the standard package manage for ruby, and Bundler is the best way to manage dependancies for your application.
Bundler is what makes you
If you don’t have the
bundler gem installed, you probably don’t have rvm installed.. You should go ahead and do that.
bundle gem is a command that will generate a template for building a gem. It will create a standard directory structure, create a git repo, and make it easy to build out gems, install them locally, and push them up to the central gem repository.
The first file to look at is the
socialinvestigator.gemspec. This defines information about your gem, a description, homepage url, the files that are included, and all of it’s dependancies. There are two types of dependencies:
- Runtime dependencies are what the gem needs to be installed and functional when its running.
- Development dependencies are additional gems needed for building the gem, which normally mean gems needed for testing and building.
Lets edit the file and add a line
Giving us something like this:
bundle to install.
Creating a binary
Now we need to create a binary in the
bin folder, which doesn’t yet exist. The line
spec.executables in the
.gemspec is what tells rubygems which files are being included and installed with the gem. The definition that the bundler gem template gives you will include all files in the
bin directory which are checked into
Now we need to make it executable,
Running the binary
Running this binary now by typing
bin/socialinvestigator will give an error. This is because it’s being called in your normal user context. The first line in the file does
require 'socialinvestigator', which is the gem we are writing, and that gem hasn’t been installed.
We can run this in the context of the gem itself, by running
You should always run your gem this way. The
bundle exec command will load all of the gems specified in the
Gemfile.lock and then start your script in that context. This is also going to be important later on, when you are working on a new version while you have an older version installed.
Thor is a toolkit for building command-line interfaces. The
bundle command itself is implemented in
thor. Thor makes it easy to expose methods in your class, with parameters and options, to the command line. Let’s see how it works.
We are going to add a new file in
The art of naming variables, classes and methods is one that I’ve honed over years of progressional software engineering, based largely on both my experience as an inheritor of other’s inexplicable code, as well as the practical jokes that I, evidently, liked to play on my future self. Also, I was inspired by The Bonhamizer
Lets make sure that we require that new file in the main
And now lets change our
bin/socialinvestigator ruby scripts to:
This creates a class/ bon mot named
Socialinvestigator::HammerOfTheGods that we can now place our code in. We’ve changed our script to call the class method
Socialinvestigator::HammerOfTheGods.start( ARGV ), which passes in the command like arguments into the Thor base class. These arguments are parsed, and Thor looks for public method on our class, with the right number of arguments, to run when passed on the command line.
Running it with no arguments will print out a list of all the commands available. In our case, only the build in
help command, and our
Lets try running our command with the wrong number of arguments, i.e. none. Here it will print out the short usage of the command that we specified with the
The built in help command will bring out usage information for the method using the
long_desc if available and the regular description if not. These are optional but why not, right? Notice also how it’s smart enough to figure out the command name, in this case
Lets now run the command as it was meant to be:
And when passing in an optional tag:
You can also mount Thor classes inside of other ones. This is handy because generally you want a few top level functions that do broad sweeping things, and then many more very specific method that do fiddly things with an API that you don’t often use.
This is done with the
subcommand method. Inside of
lib/socialinvestigator/cli.rb lets add the lines in the
And now lets create that new file
And we can now see what we have:
I wrote a bunch more code and then checked it in to github.
Getting the gem out there: Build install release
In order to install the gem, we need to build it:
This will create a gem in the
pkg directory. The version, in our case, is specified in
lib/socialinvestigator/version.rb and will need to bump it up everytime we push a release out.
Lets install the gem locally, and see if we can access what we need ourside of the working directory:
This takes the gem located in
pkg and installs it as part of our local gem set. Now we can type anywhere on our system:
Now lets release it.
This command tags the repo, pushes the commits and tags onto github, and then pushes the code to rubygems.org, where it gets its own shiny page.
Image Credit: JD Hancock