Ruby Gems and How to Make Them

Posted on November 21, 2014

A group of Winza ruby and sapphire crystal specimens collected by Vincent Pardieu while visiting the Winza gem mining area in 2008 associated with two beautiful faceted rubies seen in Paris.

A gem, in the Ruby sense, is a prepackaged program or library designed for easy installation within a system or application. RubyGems is package manager, repository, and your soon-to-be best friend behind the implimentation of these gems. I was using gems long before I understood what they really were, and today, we'll go over the process of creating and accessing our very own.

Step 1: Create an Account on Ruby Gems dot Org

The first thing we'll need to do is hop over to the RubyGems signup page and create a new account. This is our gem mine, containing thousands of gems of varying degrees of usefulness. All we need right now is a user account, but feel free to twiddle through the gem index.

After you create your account, hop back over to you terminal and login by typing gem push. You'll get an error, because we haven't specified a gem name, but that's fine as long as it says "Signed in" above that error.

Step 2: Generate Your Gem on the Command Line

Do a quick search on RubyGems to make sure no one has used your name of choice before. They have some recommendations for naming conventions that will help organize your gem for both you and any users who try to use it. I will assume you're going to follow their advice.

Back in the command line, type

bundle gem example_name

where example_name is the name of your gem. That creates the shell of our gem as well as initiates a github repository in the project folder. The folder structure of all gems is as follows:

  
  example_gem/
  ├── lib/
  │   ├── example_gem
  │   │   └── version.rb
  │   └── example_gem.rb
  ├── README
  ├── Rakefile
  └── example_gem.gemspec
  
cd into the parent folder and let's look at the good stuff.

Step 3: Edit the Gemspec and README

Open the gemspec file in your preferred text editor. It'll look something like this:

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

  Gem::Specification.new do |spec|
    spec.name          = "example_gem"
    spec.version       = ExampleGem::VERSION
    spec.authors       = ["your_name"]
    spec.email         = ["your_email@email.com"]
    spec.summary       = %q{TODO: Write a short summary. Required.}
    spec.description   = %q{TODO: Write a longer description. Optional.}
    spec.homepage      = ""
    spec.license       = "MIT"

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

    spec.add_development_dependency "bundler", "~> 1.7"
    spec.add_development_dependency "rake", "~> 10.0"
  end
  

The spec.summary is our first stop. Replace the contents of the curly brackets with a summary of what your gem is designed to do. Expand on that with a more in-depth explanation of its fuctionality in the spec.description. Be sure in both cases to remove the "TODO" as this will create havoc with your gem.

With the summary and description out of the way, we can add any dependencies that our gem might need. Think of dependencies as gems for your gem. For instance, if we wanted our gem to make api calls with Unirest, we'd throw spec.add_dependency "unirest" right above the spec.add_development_dependency "bundler", "~> 1.6" at line 21. Remember to bundle after all your dependencies are added.

Next is the README. I know; I know. You don't want to write it. I don't either, but we've all bashed our heads against our keyboards, trying to install something that incomplete documentation, what was there crafted in hieroglyphics without a Rosetta Stone in sight. And we have all shook our fists at the heavens, gnashing our teeth and cursing the nerd who thought the installation, configuration, and implementation processes were so obvious that a decent README wasn't necessary. Do not be that nerd. Take the ten minutes to write a decent README. This will also help us think about what we're about to code, the structure we'll want to achieve. This will help you; it will help me; it will help those who come after us. Do it for everyone.

The README will be in Markdown. Dillinger and StackEdit are both easy-to-use in-browser Markdown editors. That README will be done in no time.

Step 4: Our Code

This is where we throw in our reason for starting the gem in the first place. The gem we're making today is an executable on the command line, which means we need a bin folder. "Bin" here stands for "binary," the term for executable files. Going back to the gem file structure, we want to add our bin folder to the root, like so:

  
    example_gem/
    ├── bin/
    │   └── example_gem
    ├── lib/
    │   ├── example_gem
    │   │   └── version.rb
    │   └── example_gem.rb
    ├── test/
    │   └── test_example_gem.rb
    ├── .gitignore
    ├── example_gem.gemspec
    ├── Gemfile
    ├── LICENSE.txt
    ├── Rakefile
    └── README.md
  

I threw a test folder and file in there as well. Technically speaking, we can write all our code in the example_gem file in the bin folder, since our simple gem will only apply that far, but it's best practice to write your code in the lib/example_gem folder and refer to that from your executable.

For now, let's focus on the executable. Put this line at the top of that file:

#!/usr/bin/env ruby

This tells the terminal that the code in here should be run as Ruby code.Jump over to the terminal and run chmod +x bin/example_gem, which changes the bin file from one that is read-and-write only to one that is executable.

I added this code in the executable:

  
    puts "hey there"
    puts ""
    puts "  ('v')"
    puts "   \\|"
    puts "    |\\"
    puts "   / \\"
  

Step 5: Commit, Install, Release

With the code written, add and commit it to github the usual way, git add --all and git commit -m 'initial commit'. If you'd like to test your gem locally, run rake install and rbenv rehash. Rbenv rehash creates shims at the front of your PATH that pass along Ruby commands to rbenv. That accomplished, type our command and behold the glory of your first gem.

Assuming all goes well, create a repo at github and push your code up. Running rake release will upload your gem to RubyGems and make it available to the world. Congratulations! You're one step closer to Ruby mastery.

photo credit: Vincent Pardieu