This blog post was inspired by @garybernhardt’s tweet

Coming in a few minutes: my first actual Ruby gem. If I can figure out how to publish it.

In the distant past, I would have suggested to Gary that he use Jeweler when starting a new Ruby Gem. Then one day I was deep in a conversation with Durran Jordan (@modetojoy) about some minutae of MongoDB and Mongoid when the topic of starting a new gem came up. Durran’s reaction was stated with his usual aplomb:

Jeweller? Hoe? F*#!k that noise. Write your own gemspec and be done.

When Durran says something, it is worth listening to. I went back and ripped out Jeweler. The world did not end. I published my gem. I even found I had a bunch of unnecessary baggage. Getting rid of Jeweler actually improved my understanding of the gem publishing process.

How to publish your gem

Publishing a gem is basically a three step process:

Well, except for the zeroth step: deciding on a gem name. It is well worth spending a little time googling and taking a look at existing RubyGems.org before choosing your name.

Gem layout and Gemspec generation

The hard way to do this is to find another gem and copy its gemspec and layout.

Or we can cheat.

Bundler will generate a gemspec and a layout for you1. And since we are cheating already, lets use use rvm as well, shall we?2. You can follow along with this not-yet-released gem handlebars_assets3. Here is what we are going to do:

Easy!

% rvm gemset create your_gem
% rvm gemset use your_gem
% gem install bundler
% bundle gem your_gem
% cd your_gem
% cat > .rvmrc
rvm use default@your_gem

Edit .gitignore to remove Gemfile.lock from the list of ignores.

% git add .
% git commit -m 'Initial commit'

We now need to edit our generated gemspec. There are three basic parts to the gemspec:

Our generated gemspec has placeholder metadata, a good starting manifest, and no dependencies.

 1# -*- encoding: utf-8 -*-
 2$:.push File.expand_path("../lib", __FILE__)
 3require "your_gem/version"
 4
 5Gem::Specification.new do |s|
 6  # Metadata
 7  s.name        = "your_gem"
 8  s.version     = YourGem::VERSION
 9  s.authors     = ["Your Name"]
10  s.email       = ["your_name@example.com"]
11  s.homepage    = ""
12  s.summary     = %q{TODO: Write a gem summary}
13  s.description = %q{TODO: Write a gem description}
14
15  s.rubyforge_project = "your_gem"
16
17  # Manifest
18  s.files         = `git ls-files`.split("\n")
19  s.test_files    = `git ls-files -- {test,spec,features}/*`.split("\n")
20  s.executables   = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
21  s.require_paths = ["lib"]
22
23  # Dependencies
24  # specify any dependencies here; for example:
25  # s.add_development_dependency "rspec"
26  # s.add_runtime_dependency "rest-client"
27end

Edit the metadata to include your name, email, and what the gem is about. Unless you are doing something off the reservation, there should be no need to mess with the manifest.

The gemspec allows you to specify both runtime and development dependencies. Runtime dependencies are what the users of your gem will need installed with the gem. Development dependencies are used by developers working on your gem, for example gems used for testing only such as RSpec and Cucumber. Add the dependencies you know. You can change the dependency list later easily. Important! Do not edit the Gemfile, bundler knows how to read the gemspec.

% bundle
% git commit -a

Now comes the hard part, actually writing your gem.

First push

After you have written you gem’s initial code, you will want to push it out for people to use. There are two things to know about this process:

Once you have your RubyGems account, lets build and push the gem using the gem command. When you push, you will be asked to log into RubyGems one time. After that, your credentials will be saved for future use.

% gem build your_gem.gemspec
% gem push your_gem-0.0.1.gem
Enter your RubyGems.org credentials.
Don't have an account yet? Create one at http://rubygems.org/sign_up
   Email:   your_name@example.com
Password:
Pushing gem to https://rubygems.org...
Signed in.
Pushing gem to https://rubygems.org...
Successfully registered gem: your_gem (0.0.1)

Congratulations on publishing your gem!

Subsequent pushes

On subsequent pushes you will need to manage your version number. There are also two things to know about this process:

Update (but do not commit) your version number in lib/your_gem/version.rb. If you have any other outstanding changes, commit those first — we want our version number commit to be atomic and we are going to tag it. Now do this:

% bundle
% git commit -am 'v0.0.2'
% git tag 'v0.0.2'
% gem build your_gem.gemspec
% gem push your_gem-0.0.2.gem

Running bundle before the commit updates the version numbers in the Gemfile.lock file. Your git history will look nice and clean with your spiffy new atomic version commits!

Durran was right: just write the gemspec and be done.

1 Not using Bundler? Do it the hard way. Better yet, use Bundler.

2 Not using rvm? Why not? At least tell me you are using rbenv?

3 This repo is currently (8/22/11) missing the README.md, you should have one.

blog comments powered by Disqus