2020-12-29

rbenv rehashをちゃんと理解する

rbenv の rehash というコマンドについてちゃんと理解するべく調べたのでまとめる。なお調べたのはバージョン1.1.2のrbenv。

$ rbenv --version
rbenv 1.1.2

もしかすると間違っている部分があるかもしれないので、気づいた方はコメントなどいただけるとありがたいです。

rbenv rehashとは何か

rbenv rehash コマンドを実行すると、大まかには ~/.rbenv/versions/*/bin/ 以下のファイルを ~/.rbenv/shims/ 以下にコピーする。

なぜコピーする必要があるかというと、通常PATHが通っているのは ~/.rbenv/shims 以下となっているからで、ここにコピーしないと rspec とか rubocop といったGemが提供するコマンドを実行できないからである。

rbenv initがやっていること

ここで、「rbenvは使っているけど ~/.rbenv/shims にPATHを通した記憶なんて無いぞ」という人もいるかもしれないが、zshrcやbashrcといったシェル起動時に読み込まれるファイルに eval "$(rbenv init -)" と書いた記憶は無いだろうか?

README にちゃんと書かれているのだが、rbenv init - を実行することで、以下のことがなされている。

  • (1) ~/.rbenv/shims を環境変数PATHの先頭に追加する
  • (2) コマンドの補完用のシェルスクリプトを読み込む
  • (3) shimのrehash、すなわち rbenv rehash の実行
  • (4) sh dispatcherをインストールする

ここで大事なのは (1) のところで、環境変数PATHへshimsのパスを追加するということを rbenv init - により行われているということだ。

いつ rbenv rehash を実行すればいいか

ここまでの話を踏まえると、実行コマンドを含むGem (rspec, rubocop, etc..) をインストールした場合には、rbenv rehash コマンドを実行しないといけないことが想像できると思う。

なぜならば、gem install xxx と実行したときには ~/.rbenv/versions/*/bin/ の方にしかインストールされず、そこに配置された実行ファイルをパスの通っている ~/.rbenv/shims 以下にコピーしないと実行できないからだ。

....と自分は考えたのだが、この理解は少し間違っていることが後から判明した。

なぜか? 実はrbenvは gem install xxx をしたタイミングでhookスクリプトを噛ませていて、それが自動的に rbenv rehash を実行していたのである。よって自分で明示的に rbenv rehash を実行する必要はない。

rbenvの歴史はあんまり調べてないのでよく知らないのだけど、もともとは rbenv-gem-rehash というrbenv pluginがあって、それがこの動きをしていたのだけれど、今はrbenvのcoreに移植されているということのようだ。

実際に試してみた

実際に、gem install をしたときに自動で rbenv rehash が実行されていることを確認したのでご紹介。 今回は、今の自分の環境にはインストールされていなかった colorls というgemを使って確認する。

まず、gem install前の状態。colorls は存在しない。

$ ruby -v
ruby 2.7.1p83 (2020-03-31 revision a0c7c23c9c) [x86_64-darwin18]

$ ls ~/.rbenv/shims/ | grep colorls
# => 結果なし

colorlsをinstallする。

$ gem install colorls

Fetching colorls-1.4.3.gem

..snip..

Successfully installed colorls-1.4.3
Parsing documentation for colorls-1.4.3
Installing ri documentation for colorls-1.4.3
Done installing documentation for colorls after 0 seconds
1 gem installed

shims以下を見てみると、すでにいることが確認できる。

$ ls ~/.rbenv/shims/ | grep colorls
colorls

当然、コマンドの実行もできる。

2020-12-29-01.png
colorlsコマンドの実行結果

rehashをいつ実行するか?の考察

このプラグインのおかげもあり、rbenv rehash コマンドを明示的に実行しないといけないケースはそんなに多くないんじゃないかと思う。

そもそも、ログインシェル起動時のタイミングで rbenv init - により自動でrehashは実行されているので、コマンド実行するよりも新規でセッションを立ち上げたほうが楽な気すらする(tmuxとか使っていると特に)。

新しいバージョンのrubyをインストールしたときくらいかな?と今は考えている。

まとめ

  • rbenv rehashによって、rspecrubocop といったコマンドが実行できるようになる
  • rbenv rehashは rbenv init のタイミングや gem install のタイミングで裏で動いているので、明示的に実行しないといけないケースは少なそう

rbenv、よくできたツールだなぁとしみじみ思った。