Lately I switched to asdf for managing and installing my rubies.
One downside of asdf is that it, or rather its ruby plugin, does not support gemsets. I knew that before I switched. I wanted to give a gemset-less existence a try.
Mostly because I refuse to prefix every ruby executable I run with
bundle exec or create aliases for everything.
Another benefit is that you can easily nuke a gemset that was used for just one specific project, without any effects on other, unrelated projects.
But gemsets come at a price. Gems need to be installed multiple times, which slows things down.
Why do we need to use
bundle exec in the first place?
This command executes the command, making all gems specified in the
requirein Ruby programs.
If you have multiple versions of the same gem installed, say you've got both rails 5.3.2 and rails 6.1.3 installed into your global set of gems, and then run
rails server in your terminal, your shell does not know which version's
rails executable you want it to run. Rather it will run just one of them, and not necessarily the right one, which will lead to random, weird and unexpected issues.
bundle exec makes sure that everything that runs and is required is using the right gems in the version specified by your project's Gemfile and Gemfile.lock respectively.
meet bundle binstubs
Binstubs are scripts that wrap around executables. Bundler creates a small Ruby file (a binstub) that loads Bundler, runs the command, and puts it into
bin/. Binstubs are a shortcut-or alternative- to always using
bundle exec. This gives you a file that can be run directly, and one that will always run the correct gem version used by the application.
Instead of prefixing everything with
bundle exec all the time, you can alternatively make sure you run any commands by invoking its binstub. They are not generated by default, though Rails comes with a bunch of predefined binstubs out of the box.
To generate a binstub for a ruby command you run regularly, for example
rspec or maybe
rubocop, you'd just generate the binstub once, then use that:
And that's better than
bundle exec rubocop?
Well, I'd say slightly? But not good enough, let's drop the
PATH to sanity
binstubs are always going to reside in a directory called
bin inside the current projects directory. This allows me to add
bin to my shell's PATH variable, which will allow the shell to find any binstubs that are there, without me needing to tell it they are in the
I'm using the fish shell, I added this line to the bottom of my config.fish file to add
bin infront of any other paths to look in for executables:
Now, from a ruby projects directory, I can run rubocop, through its binstub, by just typing:
Given I made sure the binstub exists first.
You can double-check that the command runs the right executable script using
If the output of
which looks different, then there's either something wrong with your PATH, the binstub for that particular ruby executable is missing or you might have forgotten to reload your shell after changing PATH?
What camp are you in?
bundle exec like you don't care about superfluous characters typed, or
be alias because more obscure, but less characters ftw? Let me know! Find me on twitter @wolfgangrittner, or drop me a mail to firstname.lastname@example.org.