Isolate is a tool for managing RubyGems by including them within the project that requires them. At Goldstar, we recently switched from Bundler to Isolate for managing our gem dependencies. (I wrote about that experience here.) We have found Isolate to be stable, beautifully simple, and easy to extend. Most importantly, new developments and feature enhancements have been welcomed with open arms.
Of course, you’ll need to install the Isolate gem to get started. The usual gem install isolate will do the trick just fine. Once you have Isolate installed, you must initialize it in your project. In a Rails project, config/preinitializer.rb is a great place for this initialization code. In non-Rails projects, put the following in the file that’s loaded first, or a file that’s loaded before any gems are required.
require 'rubygems' require 'isolate/now'
That’s all that’s required for Isolate to be initialized. Isolate will now look for a file called Isolate in the current working directory. The Isolate file contains lines that describe which gems are to be installed for your application. Here’s a sample Isolate file that specifies some gem dependencies:
When Isolate runs (in the app’s initialization), it will install the latest version the chronic gem in your application.
Specifying Specific Revisions
Depending on a moving target is tricky business, as a new version of chronic could be released which breaks compatibility with your app. You can specify which version of a gem to install as the second argument to the gem method.
gem 'chronic', '0.2.3'
This will make sure that only version 0.2.3 of the chronic gem is installed. If a new version of chronic is installed, you don’t have to worry about updating your project to support it until you’re ready.
Some gems will require build arguments to be passed in order for the extension to be built properly. Using version 2.7 of the mysql gem may require build arguments to be passed in. Build arguments are passed via the :args keyword argument to the gem method. Like so:
gem 'mysql', '2.7', :args => '--with-mysql-config=/opt/local/bin/mysql_config5'
Of course, putting this in your Isolate file and checking it in is going to be problematic if different members of the team need environment specific build options. To solve this problem, Isolate will look for a file called Isolate.local which can override any of the settings in Isolate. It’s up to your team to decide on a best practice for what settings to put in the global Isolate configuration, but each developer can override those settings in Isolate.local.
A last point I want to make, for those of you migrating from config.gems or Bundler, is how to solve the auto require problem. Rails’ config.gems and Bundler both have a stupid bug which automatically requires the gem name upon installation. You may find that your code depends on this idiotic behaviour when you move to Isolate from one of these projects. You can simply add the following code to the bottom of your Isolate initialization to auto-require as gems are installed.
# FIXME: autorequire is stupid Isolate.instance.entries.each do |e| next unless e.matches? Isolate.env begin require e.options[:require] || e.name rescue LoadError => e # eat the LoadError end end
Using require ‘gem-name’ is the expected behaviour for most gems. For gems whose library is named differently from the gem, you can specify the library name to require with the :require argument to gem. For ‘mime-types’, you can use:
gem 'mime-types', '1.15', :require => 'mime/types'
If you’re not inheriting code that depends on this behaviour, please do the rest of your community a favour by not propagating it, and place your requires properly where they’re needed.
I’ve said many times that the feature I love most about Isolate is how simple it is. The entire code base is less than 800 lines of Ruby, with about half of that number being taken up by tests. As you saw in the Auto Require example, extending Isolate is painless, and the Isolate developers (a group which I am happy to be a member of) are happy to hear feedback and integrate patches. If you run into problems using Isolate on your project, please drop by #isolate on Freenode and we’ll be more than happy to help you along.