April 30, 2011 Leave a comment
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
For those interested, here’s the default structure and gem template that I use.