Tutorial

How To Package And Distribute Ruby Applications As a Gem Using RubyGems

Published on February 13, 2014
author

O.S. Tezer

How To Package And Distribute Ruby Applications As a Gem Using RubyGems

Introduction


Sharing forms a bridge between everyone involved and it makes things grow. That’s the basis for the open-source movement, which gave way and allowed so many great things to happen – especially in the recent years.

This principal applies for Ruby and Ruby based applications. That’s why - and how - a developer can get started working on making their idea a reality so rapidly, thanks to all the available tools, libraries, and frameworks that they can take advantage of.

In this DigitalOcean article, we aim to help those trying to find ways to give back to the community by sharing their own Ruby-based or Ruby-related creations. We are going to shed some light behind the mystery of packaging code for others to be able to easy download it as a Gem using the RubyGems package manager, which makes the whole process a breeze.

Glossary


1. Packaging Applications


2. RubyGems Package Manager And Ruby Gem Packages


  1. RubyGems Package Manager
  2. Ruby Gem Packages
  3. Gem Package Structure

3. Getting Ruby And Necessary Tools


  1. Installing Ruby
  2. Installing Bundler

3. Packaging A Ruby Application


  1. Preparing The Distribution Directory
  2. Creating A .gemspec File
  3. Placing The Application Code
  4. Modifying The Main Application Script
  5. Making Sure Everything Works
  6. Listing Your Gem’s Dependencies
  7. Committing The Gem Package

4. Releasing A Gem Package


  1. Creating The Package
  2. Publishing The Gem

Packaging Applications


One of the ways of distributing applications, libraries, or other programming related code bundles is to put them in archives called packages. Application packages contain already compiled and ready-to-use software in an easy-to-keep-track-of and easy-to-use way. They usually come with additional files that contain information about the package and sometimes documentation as well.

Packaging applications, therefore, consists of following a set format defined by package management tools (i.e. the RubyGems) and using these tools to share them with others in an easily accessible way.

In this tutorial, we will begin with understanding RubyGems, the Gem package format, and then learn how to package a Ruby application from start to finish, beginning with creating the package structure to contain the code (and other related material).

RubyGems Package Manager And Ruby Gem Packages


Note: The subject matter of this article is to package applications. This section contains a summary of related tools and materials. To learn more about them, you can read the introductory first part of our RubyGems series.

RubyGems Package Manager


RubyGems is the default package manager for Ruby. It helps with all application package lifecycle from downloading to distributing Ruby applications and relevant binaries or libraries. RubyGems is a powerful package management tool which provides the developers a standardised structure for packing application in archives called Ruby Gems.

Ruby Gem Packages


A Gem is a Ruby application package which can contain anything from a collection of code to libraries, and/or list of dependencies that the packaged code actually needs to run.

Gem Package Structure


Gem packages contain different sets of components. Each component gets placed inside a dedicated location within the gem bundle.

All the below elements (and more) can go inside Gems:

  • Application code;

  • Tests;

  • Description of dependencies;

  • Binaries;

  • Relevant Documentation;

  • Information regarding the package (gemspec).

Gems are formed of a structure similar to the following:

/[package_name]               # 1
        |__ /bin              # 2
        |__ /lib              # 3
        |__ /test             # 4
        |__ README            # 5
        |__ Rakefile          # 6
        |__ [name].gemspec    # 7
  1. [package_name]:
    The main root directory of the Gem package.

  2. /bin:
    Location of the executable binaries if the package has any.

  3. /lib:
    Directory containing the main Ruby application code (inc. modules).

  4. /test:
    Location of test files.

  5. Rakefile:
    The Rake-file for libraries which use Rake for builds.

  6. [packagename].gemspec:
    *.gemspec file, which has the name of the main directory, contains all package meta-data, e.g. name, version, directories etc.

Getting Ruby And Necessary Tools


Installing Ruby


In case you don’t have Ruby installed already, you can follow one of the two links below to get it properly set up on your platform of choice.

Installing Bundler


One of the tools we will be using for creating Gems is Bundler. Once Ruby and thus RubyGems are installed on your system, you can use the ``gem` command to get bundler.

Run the following to install bundler using gem:

gem install bundler

# Successfully installed bundler-1.5.3
# Parsing documentation for bundler-1.5.3
# Done installing documentation for bundler after 3 seconds
# 1 gem installed

Packaging A Ruby Application


There are several ways to start creating a Gem package. One the methods is to use the popular Bundler, a Ruby environment and dependency manager that helps with an application’s requirements and maintenance of the code. This tool can also be used to scaffold a Gem distribution directory to kick-start the packaging process.

Preparing The Distribution Directory


Gem packages are kept in package directories which should be named after your package as we have discussed in the previous structuring section. Since these are simple locations found on the file system, you can use the Unix mkdir command to create them one by one… or get Bundler to do the job.

Run the following command to scaffold all the necessary directories inside a folder, named after your Gem’s desired name:

# Usage: [sudo] bundle gem [your chosen gem name]
# Example:
bundle gem my_gem

Note: Gem names need to be unique. Therefore, you should search and make sure that the name you would like to use for your Gem is not already chosen by someone else’s project. In order to verify, you can visit and search on RubyGems.org.

The above command will run a series of commands to create our package structure, e.g.:

# bundle gem my_gem
#       create  my_gem/Gemfile
#       create  my_gem/Rakefile
#       create  my_gem/LICENSE.txt
#       create  my_gem/README.md
#       create  my_gem/.gitignore
#       create  my_gem/my_gem.gemspec
#       create  my_gem/lib/my_gem.rb
#       create  my_gem/lib/my_gem/version.rb
# Initializing git repo in .../my_gem

As you will see, Bundler has also created a brand-new Git repository which comes in handy with various versioning operations.

Note: If you would like to learn more about how to work with Git, check out the DigitalOcean community articles on the subject.

Creating A .gemspec File


The .gemspec file contains some absolutely vital information regarding Gem packages. Ever Gem must be shipped with one where meta-data from Gem name to version and description to folders to be included by Gem are found.

Tip: .gemspec files are regular Ruby scripts – which means that they are programmable.

To see the contents of the generic gemspec created by Bundler, use the following command:

cat my_gem/my_gem.gemspec

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

# Gem::Specification.new do |spec|
#   spec.name          = "my_gem"
#   spec.version       = MyGem::VERSION
#   spec.authors       = ["Maintainer Name"]
#   spec.email         = ["maintainer@email.address"]
#   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.5"
#   spec.add_development_dependency "rake"
# end
# mba:Git

You can either edit this file now, or before each time you package and publish.

In order to modify this file, you can use the following command to edit it using nano:

nano my_gem/my_gem.gemspec

This will open up the nano text editor.

One of the recommended additional information you might want to declare here is the minimum Ruby interpreter version required to run your code.

You can do this with the required_ruby_version declaration, which can be added towards the bottom end of the file for consistency.

For example:

# ..

  # Declare that the Gem is compatible with
  # version 2.0 or greater
  spec.required_ruby_version = ">= 2.0"

  spec.add_development_dependency "bundler", "~> 1.5"
  spec.add_development_dependency "rake"
end

Once you are done editing your file, press CTRL+X and confirm with Y to save and exit.

Note: Do not forget to modify the declarations that contain a “to-do” placeholder (i.e. %q{TODO:) such as the spec.description.

Placing The Application Code


Your library (or application, framework, etc.) shall always go inside the /lib directory. Inside this directory, there shall be a Ruby script named exactly the same way as your Gem. This file is the main one that gets imported when another application depends on your Gem.

The recommended and tidiest way to place your application code is to divide it into bits and place them in a directory, inside /lib, where they are used and made available by my_gem.rb to the public.

When you look at the contents of the /lib directory, you will see that the main Ruby script and a directory to contain your code is ready:

ls -l my_gem/lib

# drwxr-xr-x  3 user  staff  102 dd Mmm hh:mm my_gem
# -rw-r--r--  1 user  staff   70 dd Mmm hh:mm my_gem.rb

And the my_gem directory inside /lib comes with a version file:

cat my_gem/lib/my_gem/version.rb

module MyGem
  VERSION = "0.0.1"
end

This VERSION number is set to be automatically imported and used inside the *.gemspec file by Bundler. You can modify it here and change it to match your Gem’s current version.

You should move all your code here to be used by your application.

As an example, let’s create a Hello [name]! module.

nano my_gem/lib/my_gem/hail.rb

Place the below example inside:

class Hail
  def self.name(n = "Dalek")
    n
  end
end

Press CTRL+X and confirm with Y to save and exit.

Modifying The Main Application Script


In the previous step, we have learned that for the purposes of keeping everything in order, applications with especially a lot of classes should be separated into pieces with all elements placed inside the /lib/[gem-name] directory.

Let’s see how we can modify the main Ruby script that gets imported when somebody uses your Gem.

Run the following command to edit the imported Ruby file inside /lib using nano:

# Usage: [sudo] nano my_gem/lib/[gem name].rb
nano my_gem/lib/my_gem.rb

You will see a very short script similar to the one below:

require "my_gem/version"

module MyGem
  # Your code goes here...
end

Here, you should import all your classes and code from the /lib/[gem name] directory and use them.

In our case, let’s see how to use Hail class which we created in the previous step.

Modify your code similarly to below example:

require "my_gem/version"
require "my_gem/hail"

module MyGem
  def self.hi(n = "Default Name")
    hail = Hail
    Hail.name(n)
  end
end

Press CTRL+X and confirm with Y to save and exit.

Note: Although there is no need to make Hail an instantiable class, for the purposes of demonstration, we have made it so and left MyGem as a module to use its methods directly.

Making Sure Everything Works


Once you move your code inside and modify your main imported script, you will want to make sure everything works, naturally. The simplest way to go about doing this is to use Bundler again – and not by installing the Gem.

First, let’s enter the Gem directory and then use Bundler’s console feature:

cd my_gem
bundler console

This will load your Gem using the information from the *.gemspec and let you get to work, e.g.:

bundler console

# irb(main):001:0> MyGem.hi("Hello world!")
# => "Hello world!"

Listing Your Gem’s Dependencies


In a real world scenario, it is highly likely that your Gem itself will be dependent on others.

These dependencies are also listed in the *.gemspec file.

Run the following command to edit the file using nano:

nano my_gem/my_gem.gemspec

Add the following instructions at an appropriate block to list dependencies:

# Usage: spec.add_runtime_dependency "[gem name]", [[version]]
spec.add_runtime_dependency "activesupport", [">= 4.0"]

Press CTRL+X and confirm with Y to save and exit.

Note: You can list all necessary dependencies by repeating the instructions successively on the *.gemspec file.

Committing The Gem Package


Once your Gem is ready to be shipped, you should commit the Git repository for versioning.

Use the following command to commit with Git:

git commit -m "Version 0.1.0" 

Git, then, is going to commit all your code and give you the results:

# [master (root-commit) d4640b8] Version 0.1.0
#  8 files changed, 104 insertions(+)
#  create mode 100644 .gitignore
#  create mode 100644 Gemfile
#  create mode 100644 LICENSE.txt
#  create mode 100644 README.md
#  create mode 100644 Rakefile
#  create mode 100644 lib/my_gem.rb
#  create mode 100644 lib/my_gem/version.rb
#  create mode 100644 my_gem.gemspec

Releasing A Gem Package


Once you are happy with your Gem, you can release it to the world on RubyGems.org.

Note: In order to release your code, you will need to have an account at https://rubygems.org/sign_up.

Creating The Package


Once all is set, you can create the package using the gem tool.

Run the following to create your package:

# Usage: [sudo] gem build [gem name].gemspec
# Example:
gem build mygem.gemspec

# Successfully built RubyGem
# Name: my_gem
# Version: 0.1.0
# File: my_gem-0.1.0.gem

Publishing The Gem


There are a couple of ways to publish newly minted Gem. Either way, you will need to log-in with a RubyGems.org account so let’s start with doing that first.

Run the following command to log-in using gem:

gem push

Enter your email address, and then your password to sign in.

Note: We specifically refrain from giving a Gem-name to push so that we only log-in without performing further action.

In order to simply push your Gem, run the following:

# Usage: [sudo] gem push [gem file]
# Example:
gem push my_gem-0.1.0.gem

Alternatively, you can benefit from Bundler’s Rake tasks. You can see a full list with the following:

rake -T
  • rake build:
    Build my_gem-0.0.1.gem into the pkg directory

  • rake install:
    Build and install my_gem-0.0.1.gem into system gems

  • rake release:
    Create tag v0.0.1 and build and push my_gem-0.0.1.gem to Rubygems

If you call rake release, your package will be pushed to your set Git account and then to RubyGems.org, e.g.:

rake build
# my_gem 0.1.0 built to pkg/my_gem-0.1.0.gem.

rake release

# rake aborted!
# Couldn't git push. `git push  2>&1' failed with the following output:

# fatal: No configured push destination.
# Either specify the URL from the command-line or configure a remote repository using

#     git remote add <name> <url>

To continue, add a remote Git account:

# Usage: git remote add origin git@github.com:[user name]/[repository].git
# Example:
git remote add origin git@github.com:maintainer1/my_gem.git

Then simultaniously release your code using rake:

rake release

# ..
# Pushed MyGem

And that’s it! You can now go to RubyGems.org and check out your Gem:

http://www.rubygems.org/gems/[your gem name]

<div class=“author”>Submitted by: <a href=“https://twitter.com/ostezer”>O.S. Tezer</a></div>

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products

About the authors
Default avatar
O.S. Tezer

author

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
1 Comments


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

You confused “principle” with “principal”.

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Featured on Community

Get our biweekly newsletter

Sign up for Infrastructure as a Newsletter.

Hollie's Hub for Good

Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

Become a contributor

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

Welcome to the developer cloud

DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

Learn more