Yesterday I reached into a project I had not touched in months. When I wrote that Ruby script, it was supposed to be a one-off effort, but, as it usually goes for things like these, it had ended sticking around for much longer than anticipated.
I have RVM installed and I had installed many Rubies and done all kinds of gem manipulations. In short, the “environment” in which that project had worked was gone.
I had the “require” statements to guide me:
require ‘rubygems‘
require ‘dm-core‘
require ‘dm-timestamps‘
require ‘json‘
However, that’s not the whole story. In this specific case, DataMapper requires
more gems based on the connection string you give it.
I think we have all tried this:
- try to run a script
- see what “require” crashed the whole thing
- install some gems (hopefully with the version needed)
- repeat
Isn’t Bundler supposed to solve that problem?
Bundler
I have used Bundler with Rails 3. But that’s all configured and just automagically works. In a standalone project, there are a few things you need to do yourself.
First:
> bundle init
All that command did was to create an empty Gemfile.
Open the Gemfile with your favorite editor and add your gem dependencies. Mine looked like this:
# A sample Gemfile
source :gemcutter
gem "dm-core"
gem "dm-timestamps"
gem "dm-sqlite-adapter"
gem "json"
Then, run:
> bundle install
So far, this is all regular Bundler stuff. What about your script?
Bundler knows about all your dependencies, surely it will “require” all I need, right?
Yes and … no.
Bundler Documentation Fail
Here’s a screenshot from Bundler’s documentation
Thank you Bundler, I “require” you and now … huh … I still require all the gems I need?! I doesn’t sound very DRY to me.
What the “bundler/setup” line did was to configure the load path.
And you could do your requires manually…
If I’m writing this it’s because there’s a way. I’m just surprised that the Bundler website doesn’t seem to document this useful feature. If there are good reasons why this is not documented (tradeoffs or something) or, even, the default behavior — we can only guess.
Here’s what your script should do:
require ‘rubygems‘
require ‘bundler/setup‘
Bundler.require
The “Bundler.require” line will require all your dependencies.
One last note, do lock (bundle lock) your Gemfile so that the dependency resolution phase is skipped. It will make loading your script much faster. (this also applies to Rails projects)
[…] Jonathan Palardy explains how to use Bundler in a non-Rails app. […]
[…] here and here to get an thought on how to use bundler in a non-rails […]