Gem Version Build Status


Allows running commands in an isolated set of gems.

Useful for testing gem dependencies in your project and reproducing related bugs.

NOTE: It currently requires Bundler to setup the isolated environment, but Bundler isn't necessary to run your Ruby code in isolation.


For supported Ruby versions, check the Travis build status

(For supporting older versions, open an issue - with some info about why you are unable to upgrade).


Add this line to your application's Gemfile:

gem 'gem_isolator'

And then execute:

$ bundle


E.g. in an RSpec test:

cmd = "ruby #{File.expand_path('lib/foo.rb')}"
GemIsolator.isolate(gems: [%w(bar >=3.2.1)]) do |env, isolation|
  expect(isolation.system(env, cmd)).to eq(true)
  1. lib/foo.rb is relative to your project's current directory.
  2. system acts just like Kernel.system.
  3. You can pass custom environment variables, e.g env.merge('FOO' => '1')
  4. :gems is a list of gems you want installed

To use your project sources:

cmd = "bundle exec ruby #{File.expand_path('lib/foo.rb')}" # bundler is needed to turn project dir into gem source
source_def = ['myproject', path: Dir.pwd] # expands to use `:path` parameter in `Gemfile`
GemIsolator.isolate(gems: [source_def, %w(bar >=3.2.1)]) do |env, isolation|
  expect(isolation.system(env, cmd)).to eq(true)


  • [x] sets up temp dir with bundled gems
  • [x] allows defining which gems you need installed in the sandbox
  • [x] allows overriding environment
  • [x] allows running commands via Bundler or plain RubyGems
  • [x] allows multiple commands within same sandbox
  • [x] fails if sandbox can't be initialized
  • [ ] seemlessly allows you to run same tests using Docker
  • [ ] smart caching and/or proxy for faster gem installations
  • [ ] allows reusing same sandbox object between tests
  • [ ] release a 1.x as soon as API is useful and comfortable enough

Things to be careful about

You can run commands in 3 ways:

  1. system('foo') will search for 'foo' among the binaries of installed isolated gems first
  2. system('bin/foo') a binstubbed version of binary from isolated gems (uses Bundler)
  3. system('bundle exec foo') uses Bundler instead of RubyGems

Capturing output is not yet supported (open a PR if you're interested).

NOTE: Inside the block, the current directory is set to a temporary directory, so it's best to expand your paths outside the block.

NOTE: You might prefer to use caching, by e.g. setting a gem source or proxy. Open a feature request if you're interested in something automatic/generic.

NOTE: :gems option is an array (for each gem) of arrays (Gemfile gem keyword arguments). .inspect is used to stringify, so things should work as expected, even if you use a hash.


Just use system() commands to find out what's going on, e.g.:

cmd = "ruby #{File.expand_path('lib/foo.rb')}"
GemIsolator.isolate(gems: [%w(bar ~>1.2)]) do |env, isolation|
  # debugging
  isolation.system("gem env")
  isolation.system("gem list")
  isolation.system("cat Gemfile")
  isolation.system("cat Gemfile.lock")
  isolatior.system("ls -l")
  isolatior.system("find bundle -name 'foo'")

  expect(isolation.system(env, cmd)).to eq(true)


Run rake spec to run the tests.


Bug reports and pull requests are welcome on GitHub at

If there are no other major open pull requests (or active branches), feel free to refactor/reorganize the project as you like.


The gem is available as open source under the terms of the MIT License.