With all of my recent interest in Ruby I have been overwhelmed by the number of really awesome rubygems. I have talked about some and I will talk about even more in the future but I felt it would be important to learn how to make my own ruby gem. After all, I’d been using GitHub to update a few people’s gems without really knowing the best way to go about such things. It took longer then I expected to find the right resources for what I wanted but I came across three good articles which pointed me in the right direction:
I’m going to write about what I feel you most likely want to know when creating your first Ruby Gem.
1 File/Directory Structure
The most basic structure for a simple ruby gem would be like so:
+ gem_name/ - History.txt - README.txt - Rakefile + bin/ - gem_name + lib/ - gem_name.rb + test/ - test_gem_name.rb
This is pretty straightforward but let me explain a little. There is an outermost directory that holds everything. Source files go in lib/, executables go in bin/, and test files will go in test/.
The README.txt is essentially to providing the meta-data, installation instructions, and basic information that you would want to any person downloading your gem to read. History.txt is the common name for the Changelog.
2 Utilities to Help You
Now don’t go making these directories by hand! As you probably expected there are a number of tools to get this job done for you. These tools are gems themselves and are therefore simple to install and start working with. The two that I would suggest looking at are Hoe and the slightly more advanced newgem which even uses Hoe.
Both tools come with command line utilities that automate building this directory structure. I’ll start with Hoe, which cleverly named their utility “sow”.
$ sow first_project creating project first_project ... done, now go fix all occurrences of 'FIX' FirstProject/Rakefile:9: # p.developer('FIX', 'FIX@example.com') FirstProject/README.txt:3:* FIX (url) FirstProject/README.txt:7:FIX (describe your package) FirstProject/README.txt:11:* FIX (list of features or problems) FirstProject/README.txt:15: FIX (code sample of usage) FirstProject/README.txt:19:* FIX (list of requirements) FirstProject/README.txt:23:* FIX (sudo gem install, anything else) FirstProject/README.txt:29:Copyright (c) 2008 FIX
That was easy. It setup a structure exactly like the above but with an additional Manifest.txt file that lists all the files. Easy enough. Lets take a look at newgem:
Okay don’t get intimidated. There is a little more meat this time but I know you’re hungry. Now there is a License, some more automation with rake, configuration files for hoe, a directory for a website allowing you to describe your gem, and even some scripts to make working with your ruby gem a little easier. This seems like a great choice for real large scale gem requiring some major testing.
For the purpose of this blog post I’m going to stick to the basics. I’m not doing anything major here. I’ll stick to Hoe and begin reaping my newly sowed gem. The majority of this tutorial will still apply no matter which method you decide to choose.
A few quick items before you dive into development.
If you used Hoe and sow then you can start out by changing all the occurrences of “FIX”. Most are found in the README.txt file and one more in the Rakefile. Fill out these details as you think they should be filled out. Get these minor details out of the way before you start your work.
I would suggest setting up version control right now and making an initial checkin for your project. The choices here are huge but not necessarily critical for your project. I would suggest that you take a look at Git, Subversion, and Mercurial. I’ll be using git, and hosting my project on GitHub. Its all free, easy, and most of all fun! Tutorials for GitHub are available online, its the easiest version control system I have ever used!
Finally, since Hoe works so nicely with RubyForge you will want to setup an account and install the rubyforge gem. That takes only a few minutes. Setting up the RubyForge bundle is pretty straightforward:
# Install and Setup $ sudo gem install rubyforge $ rubyforge setup # (optional) FYI the location of the edit file $ mate ~/.rubyforge/user-config.yml # Configure and List $ rubyforge config $ rubyforge login $ rubyforge names
You should be all set to start development on your gem.
4 Gem Basics
Now that you’re setup you can develop like normal. Put your Ruby Modules, Classes, etc. into the lib folder. One thing that you will notice that Hoe did for you is setup a Class with your gem name and it defined a single constant VERSION. This value is important when the time comes to release and later update your gem. Each section has a well defined meaning. Here is what Dr. Nic had to say:
VERSION = X.Y.Z
X = major release number (MAJOR) – not backwards compatible
Y = minor release number (MINOR) – backwards compatible, additional features
Z = patch/bug fix number (TINY) – small bug fixes
Try to keep your versioning conventions uniform with these values. Then when you want to update your gem all you would need to do would be update the VERSION, and follow through with a release.
Make use of rake to automize testing, doc creation and more. I am still just learning rake so I’ll leave most of the discussion of rake for another time. However you should be aware of the following to get a list of all the functions rake can perform:
$ rake -T
5 Create the RubyForge Package
Because you’ve used Hoe all you need to do is have a RubyForge account, the rubyforge gem configured correctly, and your source files all ready to go. Create a new package on Ruby Forge, which you can do like so:
$ rubyforge create_package bogojoker regex_replace $ rubyforge config $ rubyforge names
You would replace bogojoker with your group/username and regex_replace with your package name (which will be your gem name). This is also possible to do from the RubyForge website GUI if you can’t get this working.
6 Release (Deploy) the Gem
Once the package is created you can configure Hoe to publish right to Ruby forge by editing your Rakefile:
Hoe.new('regex_replace', Rr::VERSION) do |p| p.rubyforge_name = 'bogojoker' p.developer('Your Name', 'Your Email') end
Again notice this time that ‘regex_replace’ would be the name of your package, Rr::VERSION would point to your VERSION constant auto-created when you created your directory with Hoe’s sow, and that your rubyforge_name would be your group/username for RubyForge and this case ‘regex_replace’ would be.
Uploading is now breeze, just do the following:
$ rake release VERSION=1.0.0
Where the version number is the same as the VERSION constant for your gem. Hoe will make use of rubyforge to package and upload directly to RubyForge with little to no problems. Follow this up with:
$ rake publish_docs
7 Problems / Troubleshooting
Remember when I said “little to no problems?” Well, what if you have problems? I’ll cover a few issues I had:
Where is my RubyForge Project?
Once you make an account you actually have to request to create a project and that request will get approved later in the day. You can go through with everything and host the gem on your own gem server or at least make your .gem available using ‘$ rake package’ and taking the .gem inside the newly created pkg/ folder in your gem’s directory. But once your RubyForge project is accepted you can proceed to upload using ‘$ rake release …’.
no <group_id> configured for <bogojoker>
Make sure you create the package on RubyForge and make sure it goes through. Run the rubyforge create_package command, then config, and names to see if the new package was created. Try a more unique name if it appears not to work.
no <processor_id> configured for <Any>
In this case something went wrong with your rubyforge config. Its not known to me why this may have happened but a few others have had the same problem. The solution is easy, edit the “processor_ids:” in your your ~/.rubyforge/auto-config.yml file to be the following:
processor_ids: IA64: 6000 Any: 8000 AMD-64: 1500 PPC: 2000 Sparc: 4000 Other: 9999 i386: 1000 Alpha: 7000 MIPS: 3000 UltraSparc: 5000
$ gem install regex_replace Bulk updating Gem source index for: http://gems.rubyforge.org/ ERROR: could not find regex_replace locally or in a repository
I thought I had it! Well, actually I did! It just took about 5 minutes for the my gem to be picked up and indexed. So just a few minutes later it was working! If you ever want to search the gem index you can use the following command:
$ gem search -r regex *** REMOTE GEMS *** Bulk updating Gem source index for: http://gems.rubyforge.org/ cnuregexp (1.0.0) regex_replace (1.0.0) regexbuilder (0.0.1, 0.0.0) regexp-engine (0.9, 0.8) RegexpBench (0.5.2, 0.5.1, 0.5.0) TextualRegexp (1.8.6)
Where ‘-r’ stands for remote and ‘regex’ would be replaced with your search term.
Rubygems are part of the reason for Ruby’s massive appeal. I can download and make use of incredible ruby libraries or programs with simple ‘gem install’ commands. Now that I’ve produced my own gem I have a greater appreciation for the developers that have made this so streamlined, efficient, and easy.
I think all Ruby Developers should take the time to produce a gem. Why?
- Release open source code and contribute to the Ruby community
- It will help you when you want to work on someone else’s code
- Facilitates a test-driven mindset with rake
- Work with the automatic documentation to improve the code you release
- Spur creativity. Some Ruby gems are just brilliant. I wanna see more.
I hope this helps you and encourages you to spend the time to publish some of your useful Ruby code so that others like my self can start using it.
I almost forgot, you can grab my gem, which installs the rr command in your bin by running the following:
$ sudo gem install regex_replace $ rr usage: rr [options] find replace [filenames] rr [options] s/find/replace/ [filenames]