LoginSignup
14
8

More than 3 years have passed since last update.

Bundler の動作で疑問に思っていたことが理解できた

Posted at

Bundlerの動作に疑問を持ったきっかけ

数か月前の話になりますが、@jnchitoさんの以下のQiita記事を読ませていただいて --path vendor/bundle について改めて考える機会がありました。

bundle install時に--path vendor/bundleを付ける必要性は本当にあるのか、もう一度よく考えてみよう
https://qiita.com/jnchito/items/99b1dbea1767a5095d85

この記事で特に心動かされたのは、(--path vendor/bundleを付けても付けなくても)どっちでもいいなら付けない方を好む理由として挙げられていた「systemにインストールするのがBundlerのデフォルトで、pathを指定するのがオプションだから」という一文でした。確かにデフォルト設定で問題が起きないならデフォルトのまま使うに越したことがないなぁと思います。

ただ、gemをグローバルにインストールした場合で1個だけ疑問に思った動作がありました。

上記記事にもありますが、「グローバルにインストールされる」というのはすなわち、Bundlerを使ってインストールしたgemが開発マシン内のどこでも使える状態になる(bundle installしたプロジェクト以外の場所でも使える)ことを意味します。

どこでも使えるとは、例えば静的解析ツールRuboCopbundle installでグローバルにインストールすれば、どこのディレクトリにいようがrubocopコマンドを実行できる!ということですが、自分の環境ではそのような動作にはならなかったのです…。

$ echo "source 'https://rubygems.org'\n\ngem 'rubocop'" >>| Gemfile
$ bundle install
$ bundle exec rubocop -v # bundle execを付けるともちろん大丈夫
0.75.0
$ rubocop -v # bundle execを付けないとコマンドが見つからない…
zsh: command not found: rubocop

これについて、何故そうなるのかやっと理解できました。

先に結論

  • rbenvを使用している環境の場合、bundle installしただけではshimsディレクトリが更新されない

参考
https://github.com/rbenv/rbenv/pull/638#issuecomment-59375024

  • rbenv rehashを明示的に行うことで、shimsディレクトリが更新されて、どこのディレクトリにいようがrubocopコマンドを実行できる!
  • rbenvを使用していない環境(aptで直接インストール等)であれば、今回の事象はそもそも起きない

自分の環境

  • Ubuntu 18.04.3 LTS (GNU/Linux 4.15.0-65-generic x86_64)
  • rbenv 1.1.2-4-g577f046
  • ruby 2.6.5p114 (2019-10-01 revision 67812) [x86_64-linux]
  • Bundler version 2.0.2

色々試したこと

gem install rubocopしたらどうなのか??

そもそもBundlerを経由しなかった場合どうなるのか知りたかったので試してみました。

$ gem install rubocop
$ rubocop -v # ちゃんとコマンドが見つかる
0.75.0

大丈夫そうです。ということはBundlerが原因…と思いましたが、そういえばrbenvを当たり前のように使っていたので、rbenvを使わなかったらどうなるのか試してみました。

sudo apt install rubyで入れたRubyだとどうなのか??

厳密にはrbenvでインストールするrubyバージョンと合わせるべきですが、今回は横着しました…。
rbenvを使用していないまっさらな環境で以下を実行します。

$ sudo apt install -y ruby
$ ruby -v
ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-linux-gnu]
$ sudo gem install bundler
$ echo "source 'https://rubygems.org'\n\ngem 'rubocop'" >>| Gemfile
$ bundle install # 本件と関係ないエラーが出る場合があるが、ruby-dev等 足りないライブラリをインストールすると解消する
$ bundle exec rubocop -v # bundle execを付けるともちろん大丈夫
0.75.0
$ rubocop -v # bundle execを付けなくても大丈夫!
0.75.0

なるほど、ということはrubyのバージョンに因る問題か、rbenvに何かあるのかな?

…詳細は書きませんが、rbenvでruby 2.5.1をインストールして試しても同様だったので、rbenvに何かありそうです。

rbenvの仕組み

rbenvのGitHubリポジトリを読むと、rbenvのshimsについて記述があります。
rbenvはPATHの先頭にshimsディレクトリを挿入することで、rubyのバージョンを変更した際のコマンド切替をよしなに制御してくれています。

その他参考
rbenvの使い方と仕組みについて
https://qiita.com/Kodak_tmo/items/73147ed4f0eec54d6e94

古い記事だとrbenv install実行後はshimsを更新する為にrbenv rehashを実行すること!と書いてあったりするのですが、
5年ほど前のPull requestsrbenv rehashを自動で処理するように変更されています。
なので、普段rbenv rehashを実行することはあんまりないんじゃないかなー…と思います。(違っていたらごめんなさい…)

今回の件、なんとなくshimsが更新されてないんじゃない?と思ったので明示的にrbenv rehashしたらどうだろうと思い試してみました。

$ echo "source 'https://rubygems.org'\n\ngem 'rubocop'" >>| Gemfile
$ bundle install
$ bundle exec rubocop -v # bundle execを付けるともちろん大丈夫
0.75.0
$ rubocop -v # bundle execを付けないとコマンドが見つからない…
zsh: command not found: rubocop
$ rbenv rehash # shimsディレクトリを更新すると…
$ rubocop -v # bundle execを付けなくても大丈夫!
0.75.0

思っていた動作になりました!

Pull requestsをよくよく読んだら書いてあった

先ほどのrbenv rehashが不要になったPull requestsをよくよく読んだら書いてありました!
bundle installした際 複数回rbenv rehashが実行されるのを防ぐ為にそうなっているとのこと。Bundlerの並列性の為にrbenv rehashを一回だけ処理するのは難しかったとのことです。

そもそもBundlerを使用している時点でbundle execを付けてコマンド実行すると思うので実用上何も問題は起きないと思います。ですが、引っかかっていた些細な疑問が解決して良かったです!

14
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
8