Image for post
Image for post

The Great Gemset Debate

A common topic in the ruby community is how to manage ruby versions? Whether to use the convenience of RVM or the simplicity of RBenv. I have read and heard arguments that are usually ask these:

But core to this debate about RVM vs. RBenv, the proverbial elephant in the room, is gemsets.

Overview of Gemsets

The gemset mechanism is a method to segregate gems (ruby libraries and commands). It allows juggling gem environments on the same ruby version. This is a major feature of RVM tools, and with RBenv it can be added through a plug-in. But the RBenv community discourages using gemsets, and not without good reason.

The arguments against gemsets have two reoccurring themes:

  • redundancy
  • complexity

The redundancy argument has to deal with projects, where this already a way to segregate gems using bundler with Gemfile and Gemfile.lock.

The complexity is simply: now you have to manage ruby gemsets in addition to ruby versions and project gems with bundler. And there is complexity in underlying tools, certainly with RVM to implement gemsets.

The Exceptional Niche Use Case

Now what happens if you are not using a project to lock your gems, and you have two incompatible gem versions, e.g. foo (1.4) and foo (2.3).

If this gem installs a tool that needs to be globally available, and not locked to a project directory, a gemset would be useful, as locking such a tool by a project directory would not be desirable, especially by Ops.

Though I can imagine this scenario, personally, I have yet to come across this niche use case. Ruby on Rails, might have been a candidate, where rails new command can create an initial project, but Rails has a built-in mechanism to create older project versions, provided the earlier gem of the version desired was previously installed.

However, what if that was not the case, what if you have to switch to a different gem version to use its function? This is how that thought experiment would play out in RBenv and RVM.

Niche Case with Rbenv

This is how we could do this scenario in RBenv, if rails could not create earlier versioned projects:

As you may have noticed, we would have to switch the version of the gem installed tool by editing a Gemfile, running bundle install, and then using bundle exec to use specific version tool that we specified in the Gemfile.

So, yeah, this is not intuitive. We can make it a little better with binstubs, see below.

Niche Case with RVM

This then this is how we’d do it with RVM, if rails could not create earlier versioned projects:

As you can see, this is more intuitive, you set the gemset that contains the proper version of the gem you would like to use. You get full segregation of gems per gemset.

Enter the Binstubs

In a project, bundler and corresponding Gemfile to pin your versions in place, you can assure the correct versions of the commands are used by prepending each command with bundle exec. So instead of typing rake, you would need to type bundle exec rake to get at the desired version.

Prepending each command with bundle exec is likely to get cumbersome, so Bundler’s solution for this is binstubs, using bundle install --binstubs.

This adds a ./bin directory to your project, so you can type bin/rake instead of bundle exec rake to get at the desired version. If you put ${PWD}/bin in your PATH, you then only need to type rake inside your project directory.

However this is not so secure, and you should take precautions with something like this:

export PATH="${PWD}/bin:$PATH"
hash -r 2>/dev/null || true

If you use direnv, you wouldn’t have to do alter that PATH globally, only for the directory. To create this, run the following in your project directory:

echo 'export PATH="${PWD}/bin:$PATH"' > .envrc

Conclusion

For gems managed by a project directory using a Gemfile, gemsets are redundant. Managing gems purely with Bundler can be made more intuitive using binstubs and direnv for your workflow.

Beyond project managed gems, gemsets can be useful for separating two gem versions installed in the same ruby environment, like ruby 2.4.3p205.

So there you have it, scenarios for when you might want to use or avoid gemsets. If there are any other use cases you come across for gemsets, leave a comment.

Written by

Linux NinjaPants Automation Engineering Mutant — exploring DevOps, Kubernetes, CNI, IAC

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store