The Definitive Guide for Creating Ruby Gems
After all, a successful gem makes a Ruby programmer’s life easier
Exploring the simple beauty of the Ruby language, it’s difficult to think of improvements that could be made to make programmers’ lives easier. However, this happens more than you may think, and these improvements often are shared with others in the form of Ruby gems.
A gem is a packaged library or application that can be installed with a tool known as RubyGems. So long as one’s Ruby version is at least 1.9, RubyGems has already been installed alongside the Ruby installation.
Some of the most helpful gems are Bundler, Rake, and Minitest, each with millions of downloads and just as many happy users. The hallmark of a gem is its ability to make a Ruby programmer’s life easier; if an idea has the capacity to do just that, it should be shared with the rest of the Ruby community.
For those readers who have an idea but aren’t sure where to begin, this article is for you.
Creating the Gem
First, locate the directory where the gem will be stored. When deciding where to store it, keep in mind that it is a wise idea to initialize the directory as a Git repository.
On my computer, I’ll store the directory in my Documents folder and name it
Next, navigate inside of the
hello_gem directory and create a file named
hello.gemspec. Don’t worry — this file will be examined and explained shortly.
Create another directory named
lib and inside of that directory create a file named
hello.rb. This is the first key part to understanding the structure of a gem: the
lib directory is where the code for one’s package is stored. Popular convention is to have only one Ruby file with the same name as the gem. This one file is also in charge of your gem’s code and API.
Here is a picture of my directories for double-checking purposes:
For the purposes of this guide, the code in this Ruby gem will be simple. Some of the concepts regarding file pathing will get complicated, so it’s sound to keep as much of the code as simple as possible to compensate for this.
hello.rb file and create a
Hello class. This class will have one class method for now,
greeting, and this method will invoke the
puts method with
“Hello world!” as its argument.
The code is simple but it’s enough for checking that the gem is functional.
Navigate back to the root of our directory and open
gemspec stores an immense amount of data. The author, the version, the included files, and even more is defined within it.
Gem is a Ruby class, and
Specification is the class which contains the information for a specific gem.
hello.gemspec to match the gist below, albeit with the correct information for the
date instance variables. The homepage can also be a GitHub link for those who have already initialized this project as a Git repository.
name instance method has the string
“hello_2019_unique” assigned to it. Change the
unique portion of the string to something unique so that it doesn’t share the same name as another gem, as this will cause
Let’s build and install the
Hello gem. Run the following command in the command line:
gem build hello.gemspec
Readers will see the following messages following a successful build:
After building, it’s time to install the gem. Run the following command:
gem install hello_2019_unique-0.0.0.gem
Hopefully, readers will see the following message:
The gauntlet is almost over; let’s
Hello gem in
irb and see if it works. The following picture contains the console output that one should see at this point of the article.
Next, we’re going to
require more files, examine the
files instance variable closely, and play with file pathing.
Requiring More Files
Obviously, your gem should include more than just the ability to say “Hello.” To create and include more files, a new directory matching the name of the Ruby file in the
lib directory must be created inside of the
lib directory. Navigate to the
lib directory and do that.
This is another convention of RubyGems: the additional files used for the gem are located in a directory matching the name of the Ruby file inside of
lib. Navigate into the
hello directory and create a file named
The following gist contains the code one should implement within their
Remember how to include more files in the
gemspec? Take a look at the gist again and notice what data structure the files are stored in.
files instance method cannot be appended to; rather, an
array must be assigned to it. Additionally, do not bother including directories in this list, as directories are automatically stripped from the gem during the build process.
Most gems are far larger and more complex than this example. Imagine a gem with over 50 Ruby files dispersed among nested directories. How would we assign all of these files without writing all of them by hand?
Dir class method is one of the best answers. With the
Dir class method, one can use file patterns to match and include the desired files of
lib and all of its nested directories. The return value of
Dir is an array, which is perfect since we need to assign an array to
files. Read more on
Dir before we use it.
Let’s look at some file matching patterns.
According to the previous link,
* matches any file. If we include a file extension after the
.rb, the pattern now matches all files that end with
.rb. This pattern will be used to match and collect our desired files.
** pattern is also crucial in assigning the correct files to
files. This pattern matches directories recursively and files expansively, which means that if used correctly, we can search all nested directories of
lib for the files we wish to include in the gem.
To test out the recursive aspect of
**, navigate to the
hello directory inside of
lib and create a new directory named
third_layer. Inside of the
third_layer directory, create a file named
example.rb. No need to include any code in this file as it is only for demonstration purposes.
hello.gemspec again. Navigate to the last line and enter down to a new line. Let’s test out
Dir[ with a
p method invocation. Try to output all of the files that we want to include from
lib. If any readers wish to try using
Dir on their own, don’t scroll down as the next paragraph and picture contain the solution for including all files from
As this example shows,
Dir is an extremely useful class method. To test this
Dir method more, create a file with the
.txt extension and include it in the
files alongside the
.rb files. There are a few different ways to do this, even with
Dir. Try to be as specific as possible!
Now that all of the correct files are included, it’s time to test out
hello.rb. Go to the command line and fire up the following line:
irb -Ilib -rhello
A little explanation is in order.
-I is an option that specifies the
$LOAD_PATH directory. In this case, it’s using
lib as the
$LOAD_PATH directory. The
-r option is running the file
hello.rb and requiring the gem in the current
irb session. There are many more options one can use to modify an
irb session, check out the
IRB module documentation if interested.
The output of the command line should look like the following picture.
If any readers want to
install this updated version, be sure to update
version in the gemspec.
Separating code into distinct files and adding logically ordered directories is integral to creating a gem whose code makes sense to an outsider. Additionally, understanding the pathing in your application helps in crafting well-designed, comprehensive tests.
Similarly to how we keep writing
irb in the command line and executing that program, we can include an
executable file in our gem and run the gem with a single command. Gems do this by revealing one or more executable files to the PATH of one’s shell.
To do this, navigate to
hello_gem. Then, issue the following three commands:
These three commands do the following: create the directory
bin, which houses executable files. Then, the second command creates the file
chmod stands for change mode, which in this case, changes the operation of the file to execute with the
hello in a text editor. To make this
executable actually work, we need to add a
shebang to the top of it which will indicate the beginning of an executable shell script in a specific language. Ensure that
hello matches the following code.
hello and open up the command line again. We’re going to test the
executable before we require it in the
gemspec. Run the following command in your command line:
ruby -Ilib ./bin/hello
Alternatively, one can run the command without
Since the name of the executable is
hello, the executable is executed by calling that same name. After the test has been successfully run, it’s time to include the executable in
executables array should be appended onto, in stark contrast to the
files array, which should be assigned to.
If any readers wish to
install the new gem, don’t forget to again change the version number. After the installation of the new gem, don’t forget to test it out by typing
hello into the command line. How cool is it that we can call our program with one word?
Pushing the Gem to RubyGems
Once the gem is in a usable state for others, you can
push the gem to RubyGems for others to download.
First, create a RubyGems account with this caveat: this sounds crazy, but try not to include special characters like $, %, or ! in the password. RubyGems has trouble authenticating a password that uses these characters on the command line, so it’s easier just to not use them in the first place. There are other ways to have a secure password, like varying upper and lower case letters, misspelling words, and more.
Next, run the following command in the command line.
curl -u your_username https://rubygems.org/api/v1/api_key.yaml > ~/.gem/credentials; chmod 0600 ~/.gem/credentials
This command downloads a specific API key for an account. The computer invoking the command is then associated with that specific account. In place of
your_username should be the reader’s username.
Once the API is setup,
push the gem to RubyGems with this command:
gem push hello-0.0.your_version.gem
And that’s it! The
hello gem is now available for download by anyone who uses RubyGems.
The goal of this article was to remove as many of the common roadblocks to creating your first gem as possible. There are many more essential practices inherent to making a solid gem, like TDD, using a Rakefile for task automation, and more. These are larger concepts that cannot be covered in a single article.
One of the best ways to learn how to create something is to reverse engineer it. In this case, you can read through a gem’s files, classes, and methods, to glean an absolute understanding of the logic and code that goes into making a gem. Furthermore, one can actually rewrite and refactor the code.
To this end, I suggest starting by reverse engineering a simple application, and not one like Bundler or Rubocop. I recently created a gem named EasyPortfolio, which creates a Sinatra-powered portfolio page for software engineer job applicants. This gem is simple enough to understand for a first-time gem creator but also complex enough to see the power that a gem can wield.
In conclusion, remember the hallmark of a successful gem: the ability to make a Ruby programmer’s life easier. Good luck and Godspeed, Ruby soldiers. Create something beautiful!