Others scripts
- 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 Gemfiles work.

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.

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 git.

Lets create bin/socialinvestigator now:

#!/usr/bin/env ruby -wUrequire'socialinvestigator'puts"Hello, world!"

Now we need to make it executable,

wschenk$ chmod +x bin/socialinvestigator

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

$ bundle exec bin/socialinvestigator
Hello, world!

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

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 lib/socialinvestigator called cli.rb.

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 lib/socialinvestigator.rb file:

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 hello command:

$ bundle exec bin/socialinvestigator
Commands:
socialinvestigator hello NAME # This will greet you
socialinvestigator help[COMMAND]# Describe available commands or one specific command

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 desc DSL.

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 socialinvestigator

$ bundle exec bin/socialinvestigator help hello
Usage:
socialinvestigator hello NAME
Options:
[--upcase=UPCASE]
Description:
`hello NAME` will print out a message to the person of your choosing.
Brian Kernighan actually wrote the first "Hello, World!" program as part
of the documentation for the BCPL programming language developed
by Martin Richards. BCPL was used while C was being developed at
Bell Labs a few years before the publication of Kernighan and Ritchie's
C book in 1972.
http://stackoverflow.com/a/12785204

Multi-Thor

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 HammerOfTheGods class:

moduleSocialinvestigatormoduleCLIclassHn<Thordesc"search URL","Search hn.algolia.com for a url mentioned on Hackernews"option:tagsdefsearch(url)puts"Looks like you are looking for #{url} with tags #{options[:tags]}"endendendend

Read next

See also

How much information do you bleed?
Ever wonder who is else is using your network? Or,who has actually showed up at the office?
Networking primer The simplest thing we can do to make this work is to check to see which devices have registered themselves on the network. As devices come and go, they connect automatically, so we will have a pretty good idea if people are there or not.

Since I’ve upgraded to Yosemite my computer has gotten slower and slower. When it first boots up, it is it’s old fast self, but after a few hours everything slows down. Remember the days when you needed to restart your computer to keep it working well? I had forgotten, and I wasn’t really into remembering it.
I also upgraded to Airmail 2. I get a ton of email and it used it be a lot faster than using Mail.