Making Yosemite Faster
something is up with WindowServer
- tags
- osx
Some scripts work well because they are self contained and don’t have a lot of dependancies, like the hosts on your network tracker.
Others scripts
And on those cases, its better to make a gem and use thor
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.
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 Gemfile
s 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:
Lets edit the file and add a line
|
|
Giving us something like this:
|
|
And run bundle
to install.
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:
|
|
Now we need to make it executable,
|
|
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 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:
|
|
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 hello
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
|
|
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 HammerOfTheGods
class:
|
|
And now lets create that new file lib/socialinvestigator/cli/hn.rb
:
|
|
And we can now see what we have:
|
|
I wrote a bunch more code and then checked it in to github.
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
Previously
Next