Writing your own ruby gems

I’ve recently converted several ruby on rails plugins I wrote from the old rails plugin style to be packaged as rubygems (gvis and custom change messages), which is a much preferred format these days, as tools such as bundler make package dependency a breeze. Here I’ll cover some of the best practices that I’ve come across, a few personal preferences for managing things, and how to setup a template for making writing gems the way you like dead simple.

While starting this process I tried out several gem management solutions, starting with jeweller, which I found to have far too much extra code polluting rake tasks, and tried to manage things for me a little more than I’d like. I did find it’s default readme to be perfect though for managing an open source gem on github with sections on how to contribute via forking. Bundler also provides a mechanism for creating a skeleton gem via

 bundle gem <gemname>

I quite liked the default gem layout bundler provided, along with the nice options for switching frameworks such as testing. Since bundler is a lot newer, it’s format was much more up to date with current trends in the way gems are written too. I ended up making small tweaks to the skeleton generated here, like using a readme based on jeweller’s though largely sticking to the bundler format opting for minitest, and rcov. After figuring out a nice setup, some of the best practices, and ways of managing things I can recommend are:

Keep your ruby source in the lib directory. The default require for a gem is lib/my_gem.rb (with a gem named my_gem). If your code base is big enough to require namespacing, keep a folder for each namespace, and require the given files from lib/my_gem.rb That way nothing quirky needs to be done to require your gem, and you can still organise your source code in a nice fashion.

Bundler for gem dependencies. The new kid on the block, bundler is a fantastic way to manage gem dependencies. I won’t cover how to use bundler here, though rather than keep your list of dependencies in both the gemspec and the Gemfile, instead you can simply get the Gemfile to refer to the gemspec file with one simple line of “gemspec” and bundler will handle setting up the default group for runtime dependencies, and the development group for development dependencies. I’ve opted to ignore the Gemfile.lock for gem development (though you should definitely check it in for rails application development) because you’re not testing code for a known production environment here, so you don’t need to lock your gem versions to what you might have deployed. With gem development it’s much more important to frequently update the gems you depend on, and ensure your code is compatible (by running tests), as other developers installing your gem will likely have the latest version of your dependencies (especially if they didn’t have them previously installed).

Define a constant for the gem version. I’m a fan of defining a constant MyGem::VERSION = “x.x.x” and referring to that constant in the gemspec. I find this much nicer, as it makes it much easier for other developers using your gem to find out the version they’re using, and introspect this at runtime if they’re integrating with it. As a nice bonus, whenever you bump the gem version, only lib/my_gem/version.rb need be changed, rather than change the gemspec file.

I was also keen to try out the new minitest framework, so I used that as a default development dependency and setup a rake task for running the tests (and rcov to keep tabs on my test coverage). I found minitest quite nice to work with (and it replaces testunit in ruby 1.9), though test framework is one of the places where more so than anywhere else, it’s each to their own preferences. The most important thing is that you’re writing tests.

That also brings me to a couple of important points for making a sucessful gem that others developers will want to use: write tests and documentation. Even if you don’t write perfect yard formatted inline documentation throughout the whole of your source code (though let’s be honest, writing inline comments throughout most of it, is really helping you more than anyone else) a decent readme file is incredibly useful to anyone encountering your project for the first time. Including a summary of what problem you’re trying to solve with the gem, how to install it (a must if it’s non standard), and some basic usage instructions makes all the difference between someone guessing what the heck’s your gem is even for based on the name of it (which isn’t very helpful whether you picked a sensible name, or a trendy vowel scarce one). Writing thorough tests is also quite important because it can make all the difference between your gem being instable and no more useful than some academic code that explores an interesting domain, and actually having some robust code suitable for production usage.

Now how to wrap all that best practice into a re-usable template? well hoe provides a nice format for doing that. I’d pretty much settled on a preferred setup by this point, so I didn’t pay much attention to the default setup that hoe provides, setting up one or more templates with hoe is super easy, placing your templates in ~/.hoe_template (place your default configuration into a directory called “default” in there. You can have dynamic files by simply appending .erb and putting erb code inside any of the files here. Creating a gem with this format is then as simple as

sow <gemname>

For those interested, here’s the default structure and gem template that I use.

Using MacRuby to write a .qif file converter

I heard about the MacRuby project not too long ago and was quite excited about it for several reasons, the first is  that although it’s early days yet and version 0.4 doesn’t cover the full ruby spec, it’s showing signs of being a well performing ruby implementation. Others have already gone into significant detail about the differences, but to summarise: The original ruby implementation isn’t the best at memory management for long running processes, and this is the most recent of several other implementations that provide better performance. The other reason to get excited about this is that because MacRuby is essentially the ruby language written in Objective-C (not just a bridge), it means you can utilise both ruby’s syntactical sugar and the Cocoa library to write native Mac OS X applications using ruby code. This is pretty cool to me, because Objective-C has a pretty verbose syntax, manual memory allocation, and is generally not quite as pretty to read and write as ruby code.

Of course, nothing illustrates this quite as well as seeing how short a sample (trivial) GUI program is when written with MacRuby and HotCocoa:

require 'hotcocoa'
include HotCocoa
application do |app|
  window :size => [100, 50] do |win|
    b = button :title => 'Hello'
    b.on_action { puts 'World!' }
    win << b
  end
end

The equivalent code in Objective-C is about 3 times as long, less readable and much more confusing. That’s what I love about well written ruby code: It should be clear what’s happening, and straight to the point.

I couldn’t wait to try out writing a desktop app with MacRuby, so when a colleague needed some financial data converted from .qif format to .csv I had a look for a free tool to do this on Mac OS X, but couldn’t find one that fit the bill. So after utilising a bit of regex magic to convert the files, I decided to test out just how easy it was to write a desktop app in MacRuby, by writing an app with a GUI to do the file conversion process.

After trying out using XCode to create a new MacRuby project without much luck, I found that the HotCocoa library that comes with MacRuby (0.3+) can generate a blank app for you. Once MacRuby is installed (I’m using version 0.4) you can simply type

 hotcocoa myapp

from the terminal to generate a new application, with some laid out code, just waiting for you to add the visual elements and logic you need to your app. This sets up some rake tasks for compiling the application too using macrake (MacRuby’s binaries are just like you’re used to but prefixed with mac, macruby, macrake, macgem etc) including for when your application is finished, you can package up the MacRuby framework inside the final application for distribution, so that others can run your .app file without having to have MacRuby installed on their computer.

cd myapp
macrake        # This builds and launches the .app
macrake deploy # This builds a fully packaged version ready to ship

Overall, the process was pretty simple, I added some horizontal and vertical layouts to configure the window looked, and after only a few days of reading the documentation and coding in my spare time, I came up with Qif2csv. It’s a bit rough, and I still didn’t figure out how to make a check box with the ruby syntax, though feel free to download it, and browse the source. It was fun to try out something a bit different, and it’s always good to keep building new skills. Now of course, we can all anticipate the release of MacRuby 0.5 which is a largely performance focused release, and I believe will also support native threading.

Follow

Get every new post delivered to your Inbox.