cult3

Creating a Ruby Gem

Aug 19, 2015

Table of contents:

  1. Intall Bundler
  2. Create the new Gem
  3. The Gemspec
  4. The Gem’s version
  5. The Gem’s code
  6. Releasing your Gem

One of the beautiful things about working in the software industry is the world of Open Source. I don’t think there is another industry that shares quite as much knowledge and work as we do.

This is wonderful because if you face a problem, there’s a good chance that somebody out there has faced that problem too.

With Open Source software, we can pull in a ready made solution to our problem without having to reinvent the wheel for every new project.

However this presents a problem. How do we package and distribute code as Open Source so that it will work within the projects of others?

Fortunately this problem has been solved for a long time. Ruby has the concepts of “Gems”.

A Gem is an Open Source package that can be pulled into your Ruby project. You can find all of the available Gems at Ruby Gems.

And to manage the dependencies of a project, we can use Bundler.

In today’s tutorial we will be looking at how to build and distribute our own Ruby Gems so that they can be used by other Ruby developers.

Intall Bundler

As we saw a couple of weeks ago in Understanding and Using Ruby Rake, the first thing we need to do is to install Bundler. Once again this should be pretty straight forward if you’ve already got your Ruby environment set up:

$ gem install bundler

Create the new Gem

One of the important things about creating and releasing Gems is that all Gems should follow the same standards. This makes it possible to use Gems as interchangeable packages within other projects.

Instead of creating the required files and directories by hand, Bundler provides a command that will do this job for you:

$ bundle gem todo

If this is your first time creating a Gem you will be asked a couple of questions. The answers to these questions don’t really matter as we can change them later. We also won’t be looking at testing today, so you can just ignore the tests.

This will create the following files:

todo/Gemfile
todo/.gitignore
todo/lib/todo.rb
todo/lib/todo/version.rb
todo/todo.gemspec
todo/Rakefile
todo/README.md
todo/bin/console
todo/bin/setup
todo/LICENSE.txt

The Gemspec

The first file we will look at will be the todo.gemspec:

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

Gem::Specification.new do |spec|
  spec.name = 'todo'
  spec.version = Todo::VERSION
  spec.authors = ['Philip Brown"']
  spec.email = ['phil@ipbrown.com']

  spec.summary = 'TODO: Write a short summary, because Rubygems requires one.'
  spec.description = 'TODO: Write a longer description or delete this line.'
  spec.homepage = "TODO: Put your gem's website or public repo URL here."
  spec.license = 'MIT'

  # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
  # delete this section to allow pushing this gem to any host.
  if spec.respond_to?(:metadata)
    spec.metadata['allowed_push_host'] = "TODO: Set to 'https://mygemserver.com'"
  else
    raise 'RubyGems 2.0 or newer is required to protect against public gem pushes.'
  end

  spec.files =
    `git ls-files -z`.split("\x0").reject do |f|
      f.match(%r{^(test|spec|features)/})
    end
  spec.bindir = 'exe'
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
  spec.require_paths = ['lib']

  spec.add_development_dependency 'bundler', '~> 1.10'
  spec.add_development_dependency 'rake', '~> 10.0'
end

This file includes meta data about your Gem such as it’s name, description as well as details about it’s author (you).

Next there are instructions for how the files should be read. You probably won’t need to do anything with these files unless you are doing something that requires extra files.

Finally we have the dependencies of the Gem. This Gem has no dependencies but if it did, they would be listed here.

Dependencies can be either for development or for runtime. A development dependency would be something like a testing framework. A runtime dependencies would be something that your Gem needed to use into order work at runtime, for example an HTTP client.

These dependencies are also Gems made by other people and would be listed on Ruby Gems.

The Gem’s version

The actual code for your Gem lives under the lib directory.

You will see by default that you should have some files automatically created for you:

lib/todo/version.rb
lib/todo.rb

The version.rb file simply contains the version number of your Gem. Versioning is a very important concept in the world of Open Source Software as it is the basis for including third-party code into your application.

module Todo
  VERSION = '0.1.0'
end

Versioning should follow Semantic Versioning. This concept is out of the scope of this tutorial, and so if you are unfamiliar with Semantic Versioning, I would recommend you read up on it.

The basic premise is that the version number should follow a consistent set of rules. So if your Gem includes breaking changes, consumers of that Gem won’t be affected until they choose to be.

The Gem’s code

Next, the lib/todo.rb file is where your code lives:

require 'todo/version'

module Todo
  # Your code goes here...
end

By default this file simply contains an empty module named after your Gem as well as the version file we just looked at.

This is the file that kicks off the execution of your Gem as it is what will be included by default.

For small Gems you might want to put everything in this one file. For example, if your Gem just included a couple of methods or a couple of simple classes.

However, for bigger Gems you will want to break your code into different files and then require them in this file.

Releasing your Gem

The whole point of writing a Gem is to release it as an open source project so other people can use it too.

This involves a couple of steps.

First you should push your code to Github. Github has become the home of Open Source software over the last couple of years. It also includes a lot of excellent tools for dealing with issues, pull requests and collaboration on code development, so if you don’t already have an account, you really should get one.

Next create an account on Ruby Gems.

Then run this command in terminal:

$ bundle exec rake release

This will ask you to authenticate using the credentials you just created on Ruby Gems.

Once your Gem has been uploaded to Ruby Gems it will have it’s own page that includes details of the package. This page will be automatically updated as you continue to develop your package.

The page will also list details for how other Ruby developers can pull in your code to their projects using their Gemfile.

Philip Brown

@philipbrown

© Yellow Flag Ltd 2024.