What is gem? Why do we like it so much?

My first foray into slightly deeper techery came in the form of “dual-booting” Redhat Linux on my family desktop pc. I downloaded the image and burnt it to a cd. I painstakingly avoided any instruction whatsoever and restarted my computer. What followed, was an unceremonious wiping of every system file, family photo and bit of music I had installed on that poor, poor pc. From there, I was presented with a clean install of the coveted Redhat. The story doesn’t end there. What followed was a repetition of that process over and over again as I learned how to install an mp3 player without completely destroying everything around it.

I am the incorrigible mass of users coming from windows (and now Apple) that can’t be bothered with building from source, managing dependencies, or updating software. I am the reason you have package management across almost every operating system and modern programming language, and I am the reason you have Ruby Gems.

Ruby Gems, a package manager, managing versioning, dependencies and the installing and removing of software packages built for Ruby, is my savior. It keeps track of all major ruby packages and libraries and makes them easily accessible through a single portal.

So what tends to happen with people like myself, is that you start out taking advantage of this huge collection of other people’s work. You build things, hacking together different pieces until you have some semblance of what you were going for. But, you reach a certain point where you either need something that doesn’t exist, or you really just want to contribute to this huge collection and it’s community.

What is a gem?

At its simplest form, a gem is a specification.

Gem::Specification.new do |s|
  s.name        = "TYLER"
  s.version     = "0.0.1"
  s.date        = '2013-02-19'
  s.summary     = "Exceptions done right."
  s.description = "Exceptional exceptions!"
  s.authors     = ["The Flatiron School"]
  s.email       = "tyebud@gmail.com"
  s.files       = ["lib/tyler.rb"]
  s.homepage    = "http://rubygems.org/gems/tyler"
end

A gem is a software package that can be bundled then deployed to the RubyGems database. It contains meta data outlining the name and description of the included package, the version and any dependencies required to successfuly implement it.

How to build a gem

For this example, I’ll be going over the steps I took in making the venerable gem, TYLER.

The first step in any project is to define its purpose and scope. To do this, we need to assess our needs and decide what problems we are going to solve.

TYLER is a ruby core modification that is designed to increase readability of exception messages and in general, make debugging more enjoyable for beginners. As a beginner, deciphering exception messages can be challenging and frustrating. This can slow people down. In order to hopefully alleviate some of this stress, my colleagues and I came up with the idea to overwrite the default exception messages to be both descriptive and humorous. And thus, TYLER was born.

tyler.rb’s guts

class NoMemoryError
  def to_s
    responses = ["I've got nothing.", "Fuggedaboudit.", "Amnesia, or are you just an idiot?"]
    return responses[rand(responses.length-1)]
  end
end

As you can see, the exception subclasses’ to_s method has been over-written to accommodate an array of possible responses. From these responses, we call a random index of that array which is then returned to the user.

In this example, the entire project was encapsulated in a single file. The beauty of Gem is that, since the file variable is an array, you can pass multiple files:

s.files = Dir.glob("{bin,lib}/**/*") + %w(LICENSE README.md ROADMAP.md CHANGELOG.md)

Any specific dependencies can be added like so (do not add the actual library to your gem):

spec.add_dependency('log4r', '>= 1.0.5')

According to the specification, all library files should go in your lib folder within the project. You can have any type of file structure within this folder, as long as your source is there. At this point, my project folder looks like this:

├── lib
│   └── tyler.rb
├── readme.md
└── tyler.gemspec

Building your gem

At this point you’re painfully close to having your very own gem. You’ve got the finish line in sight, and assuming you’ve done everything up to this point correctly, passing the following should work.

gem build tyler.gemspec

If everything went well, you’ll see the following return:

gem build tyler.gemspec
Successfully built RubyGem
Name: TYLER
Version: 0.0.1
File: tyler-0.0.1.gem

If you don’t see something like this, gem’s build script does a very good job of identifying the error so that you can resolve it. When I first attempted to build TYLER, I’d defined a class with a lowercase name. Gem didn’t like that. Bad TYLER.

Installing your gem

One step closer. You can smell the champagne. Your adoring fans are cheering for you across the finish line. It’s time to test your gem. To install your gem locally:

gem install ./tyler-0.0.1.gem

Now, fire up irb and run require 'TYLER'. If everything goes according to plan, you should have a new, beautifully pretentious irb.

For anyone interested in contributing to TYLER, feel free to fork the project on Github.

In my next article, I will discuss open source projects, pushing TYLER to rubygems and github.

StatusPage is hiring engineers in San Francisco, Denver and Durham. If you'd like to be part of our incredible team, follow the link, or shoot me an email at tyler at statuspage dot io. We'd would love to chat with you.