Last Updated: June 08, 2022
·
30.56K
· mislav

Generate only the binstubs that your project needs

When you generate all binstubs for a bundle:

bundle install --binstubs

Your ./bin directory will get populated with binstubs for every gem in the bundle that has executables. However, you won't need most of those binstubs since developers generally just use a few like rake, rspec and similar.

Moreover, the --binstubs option is sticky, meaning Bundler will keep adding binstubs for new gems in the future when you run just bundle install. This can get tiresome if you checked the ./bin directory in version control (which you should), because git will keep displaying new untracked binstubs—most of which you probably won't care about—and you'll be forced to either gitignore them or add them to version control as well.

A much more thoughtful and controlled approach is to generate only the binstubs that you actually need:

bundle binstubs rake
bundle binstubs rspec-core
bundle binstubs cucumber

Now check these files in version control once and you don't have to worry about babysitting the ./bin directory in the future.

See Understanding binstubs for a broad overview of the purpose of RubyGems, rbenv and Bundler binstubs, and how you can use them to avoid having to prefix everything with bundle exec.

7 Responses
Add your response

Question,

after reading the Understanding binstubs article, I tried your tip of adding export PATH="./bin:$PATH" to my bash_profile

But, in a new shell window, when I run rbenv which rake inside my rails project, I am shown:

/Users/julieng/.rbenv/versions/2.0.0-p247/bin/rake

Is that correct? I expected it to show me the rake binstub in my projects bin folder.

Am I misunderstanding something?

over 1 year ago ·

The rbenv which command is not PATH-aware; it just looks at the currently selected version to find the rake executable. This doesn't reflect what would actually be run when you run rake, though.

Your PATH is correct, so running which rake should show /path/to/yourproject/bin/rake, which means everything is as you wanted. Now all calls to rake in your project will activate the local binstub and not ~/.rbenv/versions/2.0.0-p247/bin/rake.

over 1 year ago ·

which rake still doesn't show the local rake…but rather the shim.

I checked rbenv's Unterstanding Shims and it seems that is wanted behavior, that the shims are before other PATH.

Assuming that, would my local rake ever take precedence (see console log below)?

Or is everything working behind-the-scenes correctly and I shouldn't expect which rake to show my local rake? When you run the command in your projects, do you get your local rake? Then maybe it's me…

Sorry for all the newbie questions!

$ echo $PATH
/Users/julieng/.rbenv/shims:./bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/opt/X11/bin

$ ls bin/
bundle* guard*  rails*  rake*

$ which rake
/Users/julieng/.rbenv/shims/rake

$ rbenv which rake
/Users/julieng/.rbenv/versions/2.0.0-p247/bin/rake

Edit: commands were executed inside my rails project folder root.

over 1 year ago ·

You want the local executables (bin/rake) to have precedence over global ones, including rbenv's shims. That means you want ./bin at the very front of your PATH.

Whenever you're thinking how to order things in your PATH, it helps to think about your priorities. Ask yourself, what do you want to happen when you type rake:

  1. You want the local binstub (bin/rake) to get activated if it exists, as it guarantees that the correct rake version will be activated;
  2. If a local binstub doesn't exist, you want rbenv's shim to get activated, as it guarantees that it will get executed with the correct version of Ruby for this project;
  3. Then, for non-Ruby commands, you want /usr/local/bin to be searched because that's where Homebrew lives (if you use it), or other software that you install manually;
  4. Finally, you want system paths such as /usr/bin to get searched.

Considering the above, it means your PATH would then be (pseudo-code):

./bin : (rbenv shims) : /usr/local/bin : /usr/bin

Also, just a heads-up for the future, which rake might not show you the correct result if you've just changed PATH in this shell. This is due to caching; some shells cache the location of rake for performance reasons. So after you change PATH, you should call hash -r in your shell just in case, or use command which rake which actually calls the which executable on the filesystem rather than which shell built-in. You have every right to be confused; this stuff is hard! :(

over 1 year ago ·

Yes, I am trying to get the PATH you typed above to work.

./bin : (rbenv shims) : /usr/local/bin : /usr/bin

But from what I understand, it's not possible because rbenv always enters the shims before all other PATHs

Anyway, I find the tip to enter ./bin to the PATH. I just can't get it to work and will give up for now. But thanks for all your help :-)

over 1 year ago ·

rbenv always enters the shims before all other PATHs

Aha, now I finally understand what you're struggling with. rbenv does add the shims to the front of PATH, but it does so only at the point where you call rbenv init in your .bash_profile:

eval "$(rbenv init -)"

If you edit your PATH after this point, you will be able to add paths in the front:

export PATH=./bin:"$PATH"
over 1 year ago ·

Maybe you could add that you can add --path flag to the binstubs command, since it's not documented (in case you are interested in putting the binstubs in another directory of course).

over 1 year ago ·