Working on a Rubygem developed by another person is almost always a struggle, you have to waste an hour or two to get an environment set up so that you can run the gem’s test suite to ensure you have a known, good environment before you start to make changes. But making your gem easy for others to hack on is not hard if you follow a few simple best practices. I recently updated the mysql2 project to use these steps.
Use RVM
RVM is a no brainer for all Rubyists these days. If you aren’t familiar with it, please give it a test drive. With RVM, we can easily create a gemset which provides you a pristine development environment. I always create an .rvmrc file in the root directory like so:
rvm use 1.9.2@ --create
With RVM, we can also easily switch rubies if you want to ensure the gem works on Ruby 1.8, Ruby 1.9 and JRuby for instance.
Use an intelligent .gemspec
Rubygems requires a gemspec to describe how to build your project’s gem but this file can be a pain to maintain; give it some smarts to minimize your manual labor. Using mysql2 as an example:
require './lib/mysql2/version' Gem::Specification.new do |s| s.name = %q{mysql2} s.version = Mysql2::VERSION s.authors = ["Brian Lopez"] s.date = Time.now.utc.strftime("%Y-%m-%d") s.email = %q{seniorlopez@gmail.com} s.extensions = ["ext/mysql2/extconf.rb"] s.extra_rdoc_files = [ "README.rdoc" ] s.files = `git ls-files`.split("\n") s.homepage = %q{http://github.com/brianmario/mysql2} s.rdoc_options = ["--charset=UTF-8"] s.require_paths = ["lib", "ext"] s.rubygems_version = %q{1.3.7} s.summary = %q{A simple, fast Mysql library for Ruby, binding to libmysql} s.test_files = `git ls-files spec examples`.split("\n") # tests s.add_development_dependency 'eventmachine' s.add_development_dependency 'rake-compiler', "~> 0.7.1" s.add_development_dependency 'rspec' # benchmarks s.add_development_dependency 'activerecord' s.add_development_dependency 'mysql' s.add_development_dependency 'do_mysql' s.add_development_dependency 'sequel' s.add_development_dependency 'faker' end
Notice a few things:
/version
file which contains just the version for your project. The gemspec can just refer directly to that constant.Time.now
to dynamically set the date.git ls-files
to dynamically create your gem’s filelist.Use bundler
Use bundler to install development dependencies for your gem. Typically gems have runtime and development dependencies where runtime dependencies are necessary for the proper operation of your gem and development dependencies are necessary for testing, benchmarking, and other developer tasks. gem install
will install just runtime dependencies. But in our case, we want a way to install all the dependencies after we’ve cloned the codebase so we can run those developer tasks. All we need is a minimal Gemfile which references our gemspec and then bundle install
will install both types of project dependencies. Here’s mysql2’s Gemfile
:
source :rubygems gemspec # DRY! No need to repeat the gem deps here
Document Anything Else!
If your gem requires any further environmental configuration, document the necessary steps. A paragraph in your README about how to set up a proper development environment can help a lot, especially to a busy developer who just wants to create a quick fix for a bug.
Conclusion
With all this done, anyone with mysql and bundler installed can run the test suite (hopefully green!) on the mysql2 project with just a single line:
git clone git://github.com/brianmario/mysql2.git && cd mysql2 && bundle install && rake
Once the test suite runs green, the hacking can begin!