Tutorial: How to make a Rubygem

12th May 2013

This is the first of 3 tutorials about how to develop a Rubygem, from getting set up through to publication. In this post we'll cover the basics steps of building a gem and using it on your local machine.

Getting started is simple thanks to the tools baked into Bundler and Git, both of which you'll need to install if you're following along.

$ sudo apt-get install git
$ sudo gem install bundler

Alright, let's get cracking. For this tutorial we're going to create a simple gem called listless, which takes a Ruby Array and coverts it into a HTML unordered list. Bundler ships with a handy utility for setting up new gems, which we'll take advantage of to generate the boilerplate files and structure we need. Run the command:

$ bundle gem listless

You should see a new directory appear containing the following files:

$ tree listless
listless
├── Gemfile
├── lib
│   ├── listless
│   │   └── version.rb
│   └── listless.rb
├── LICENSE.txt
├── listless.gemspec
├── Rakefile
└── README.md

For now, the most important parts are the lib directory (which will contain our code), and the listless.gemspec file (which defines the metadata for our gem).

Adding the code

By convention a Rubygem should always have a file in the lib directory with the same name as the gem – it's this file that gets automatically loaded whenever someone requires the gem in their code.

In our case Bundler has already created the template lib/listless.rb file for us, which we'll now edit to include our logic.

We'll keep the code nice and simple for now – essentially all we want to do is run a command like Listless.ul['foo', 'bar'] and receive the unordered list <ul><li>foo</li><li>bar</li></ul> in return. We'll also use the external HTMLEntities gem to make sure any content gets encoded properly.

File: lib/listless.rb
require "listless/version"
require "htmlentities"

module Listless
  extend self

  def ul(array)
    list = array.map { |x| tag(:li, escape(x)) }.join
    tag(:ul, list)
  end

  private

  def tag(element, string)
    "<#{ element }>#{ string }</#{ element }>"
  end

  def escape(string, entities = :named)
    coder = HTMLEntities.new
    coder.encode(string, entities)
  end

end

Completing the Gemspec

Every Rubygem should include a Gemspec file, containing essential metadata like the version number, documentation links, and the gem's external dependencies. We rely on this when packaging our project into an actual .gem file in the next section, and it also provides important information to Rubygems.org and other users when we publish it later.

Again, Bundler has taken care of creating the listless.gemspec template for us and pre-filled most of the information. Let's finish it off by completing the description, summary and homepage fields, and add the HTMLEntities gem as a dependency at the bottom of the block.

File: listless.gemspec
# -*- encoding: utf-8 -*-
lib = File.expand_path('../lib', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'listless/version'

Gem::Specification.new do |gem|
  gem.name          = "listless"
  gem.version       = Listless::VERSION
  gem.authors       = ["Alex Edwards"]
  gem.email         = ["ajmedwards@gmail.com"]
  gem.description   = %q{A gem for converting Ruby Arrays to HTML unordered lists}
  gem.summary       = %q{Convert Arrays to HTML lists}
  gem.homepage      = "https://github.com/alexedwards/listless"

  gem.files         = `git ls-files`.split($/)
  gem.executables   = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
  gem.test_files    = gem.files.grep(%r{^(test|spec|features)/})
  gem.require_paths = ["lib"]

  gem.add_dependency "htmlentities"
end

Building the Gem

By now you've probably noticed that a Git repository was initialised for us when we setup our gem, and the Gemspec file leverages this to avoid manually listing out all the different files our gem contains.

So before we build our gem, we first need to make sure that all our files and changes have been committed into Git.

$ git add .
$ git commit -m 'initial commit'

Now we're ready to build the actual gem package.

$ gem build listless.gemspec

If the build completes successfully you should see a listless-0.0.1.gem package appear in your directory.

Using it locally

There are two main options for using a gem locally. The first is to simply install it alongside all the other gems on your local machine.

$ sudo gem install --local /path/to/listless-0.0.1.gem

Let's do that, then give it a quick check at the IRB prompt to make sure everything works as expected.

$ irb
$ irb(main):0001:0> require 'listless'
=> true
$ irb(main):002:0> Listless.ul ['foo', 'bar', 'báz']
=> "<ul><li>foo</li><li>bar</li><li>b&aacute;z</li></ul>"

Alternatively, if you want to use the gem in another project, you can reference the gem directly in the project's Gemfile instead using the :path option For example:

File: Gemfile
source 'http://rubygems.org'

gem 'sinatra'
gem 'listless', :path => '/path/to/listless'

Wrapup

Hopefully this tutorial has de-mystified the basic process behind building a gem, and given you an understanding of the main components. In the next post we'll get our gem ready for publication, adding tests using RSpec and documenting it with YARD.

You can find the full source code for this gem on Github.

Filed under: ruby, tutorial