ちゃんと理解するrbenv : (4) shimsを理解する
はじめに
本記事は、「ちゃんと理解するrbenv」の第4回です。
※ 前回の記事
今回は、rbenvにおける重要な概念である shims について整理します。
shimsとは
shimsは rake
、rubocop
、rspec
などといったRubyのコマンド単位で生成される実行可能なシェルスクリプトです。rbenvによって作られています。
shimsは通常、~/.rbenv/shims
以下に配置されています。筆者の環境の ~/.rbenv/shims
は次のようになっていました。
$ ls ~/.rbenv/shims
bundle htmldiff nokogiri rbs rubocop solargraph y2racc
bundler irb racc rdoc ruby thor yard
erb kramdown racc2y reverse_markdown ruby-parse tilt yardoc
gem ldiff rake ri ruby-rewrite typeprof yri
shimsには全てのバージョンのRubyの実行可能コマンドが配置されます。
例えば 2.7.3 でrubocopをインストールし、3.0.1 でrspecをインストールした場合、shimsディレクトリにはrubocopとrspecの両方が配置されることになります。
shimsの役割
rubocop
を例にして説明します。
通常、rubocop
コマンドを実行するとrubocopというgemが提供する実行可能ファイルが実行されます。
rbenvを使っているとその実行可能ファイルは ~/.rbenv/versions/X.X.X/bin/rubocop
に配置されています (X.X.X
の部分はバージョン)。
しかし、rbenvを使っている環境においてはshimsに配置された ~/.rbenv/shims/rubocop
が最初に呼び出されます。
こうして実行されたshimが何をしているかというと、
- 現在のRubyのバージョンを特定する
- 特定したバージョンのRubyの本来の実行可能ファイルである
rubocop
コマンドを実行する
ということをしています。
上の図のように、複数のバージョンのRubyがありその全てで rubocop
をインストールしている場合でも、rbenvのshimを介すことで適切なバージョンのRubyを選択し、その先の rubocop
コマンドにディスパッチすることが可能になります。
環境変数PATHとshims
これまで整理してきたようにshimsを機能させるには、Rubyのコマンドが呼びされたとき 必ず最初にshimが実行される ようにしないといけません。rbenvはこれをどのようにして実現しているでしょうか?
第2回 基本的な使い方 のときにrbenvの初期設定として、.zshrcファイルに eval "$(rbenv init -)"
という設定を追記したことを覚えているでしょうか。実はこの rbenv init
を実行することで、環境変数PATHの先頭に ~/.rbenv/shims
を追加するということが裏で行われています。
以下は筆者の環境におけるPATH環境変数の値です。PATHの先頭にshimsへのパスがあることがわかります。
$ echo $PATH
/Users/mogulla3/.rbenv/shims:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:...(省略)
環境変数PATHは、rubyに限らずシェル上で実行されたコマンドを探すときのパスの一覧が :
区切りで記述されています。このとき前にあるパスほど優先されます。
よって、一番先頭にあるshims以下に存在すれば必ず最初に実行させることができる、という仕組みになっているのです。
rbenvはいつshimsを作るのか
ところで、shimsディレクトリ以下のスクリプトはいつどのようにして作られるでしょうか?これも当然rbenvがやっているわけですが、これはrbenvの rehash という処理が行われたタイミングで作られています。
そしてこのrehash処理も rbenv init
により呼び出されています。
rehashの詳細については rbenv rehashをちゃんと理解する という過去の記事に書いているので、興味のある方は参考にしてください。
まとめ
本記事ではshimsを中心にして関連する概念の整理をしました。
- shimsは、Rubyのコマンド単位で生成される実行可能なシェルスクリプト。通常
~/.rbenv/shims
以下に配置される。 - Rubyのコマンドを実行すると、最初にshims以下のスクリプトが実行される。その後にRubyバージョンを特定した上で、shimから本来のコマンドが呼び出される
rbenv init
はshimsのパスを環境変数PATHの先頭に追加するということと、rbenv rehash
によりshimを生成する仕事をしていた
余談ですが、shimという単語には「部品の間にはさんで水平にしたり高さや位置を調整する板」とか「詰め木」という意味があるようです。最初、筆者はshimという見慣れない単語を見て ?
となりましたが、このように役割を理解するとピンと来る名前だなぁと感動しました。rbenvのshimもコマンド実行と本来の実行可能ファイルの間に入り込んで、交通整理をしていますよね。