Automating bundle exec
Bundler is a program for installing the libraries (i.e. gems) that a Ruby application depends on, in a sandbox. By specifying an application's dependencies with Bundler developers can guarantee that only specific versions of the dependencies are used when the application is running on a user's computer, or when deployed to a web server.
Quick instructions
Before I get into the nitty gritty of how it works, here are the quick installation instructions:
$ curl -L https://github.com/gma/bundler-exec/raw/master/bundler-exec.sh > ~/.bundler-exec.sh
$ echo "[ -f ~/.bundler-exec.sh ] && source ~/.bundler-exec.sh" >> ~/.bashrc
Read more on the GitHub page.
How bundler-exec works
Once bundler-exec is configured, it replaces a bunch of common Ruby
commands (e.g. rake
, ruby
, rails
, rspec
) with a shell function
that will:
- Check whether your current directory is within a bundled project (it
checks for a
Gemfile
in your current directory, or one of its parents), and - Run the command you entered, prefixing it with
bundle exec
if appropriate.
It does this with the magic of shell aliases (and therefore only works
with Bourne style shells, or shells that support the alias
command).
Browse the code on GitHub; it's very simple stuff. The full list
of commands that it looks after for you is currently:
cap
capify
cucumber
heroku
rackup
rails
rake
rspec
ruby
shotgun
spec
spork
thin
unicorn
unicorn_rails
You can easily override that list by setting BUNDLED_COMMANDS
in your
~/.bashrc
file before ~/.bundler-exec.sh
gets loaded, like this:
BUNDLED_COMMANDS="ruby rails"
[ -f ~/.bundler-exec.sh ] && source ~/.bundler-exec.sh
If you need to add commands that are in common use, please fork the project, add them to the script, and send me a pull request. Cheers!
To check whether bundler-exec
is configured, check what your shell
will do if you run Ruby. It should tell you that Ruby has been aliased,
like this:
$ type ruby
ruby is aliased to `run-with-bundler ruby'
What can go wrong if you forget bundle exec?
Remembering to run bundle exec
is a pain, can be easy to forget, and
no end of subtle bugs can occur if you forget it.
Imagine that your project requires version 1.0.0 of a gem, but you've got both 1.0.0 and 1.0.1 installed. It all goes south like this:
- Your shell will find the command that shipped with 1.0.1, and run it.
- The command will load your application code, which calls
Bundler.require
orBundler.setup
. - Bundler (quite rightly) complains when it tries to load 1.0.0 and finds that 1.0.1 is "already activated").
Avoid the ball ache, get bundler-exec!