direnv

direnvとruby-installでRubyを管理する

direnvは単なるシェルの拡張であり、今いるフォルダによって環境変数を管理します。 この記事では、ruby-installと組み合わせて使うことで、プロジェクトで使いたいrubyのバージョンを管理したり選択したりする方法を見ていきます。

準備

まずdirenvをインストールしてください。 以下はOSXとBashを使っている場合の簡単な手順です。

brew install direnv
echo 'eval $(direnv hook bash)' >> .bashrc
exec $0

それからruby-installを使って、いくつかrubyのバージョンをインストールしてください。 また、便宜上エイリアスを作ります。

brew install ruby-install
ruby-install ruby 1.9
ruby-install ruby 2.0
cd ~/.rubies
ln -s 1.9.3-p448 1.9.3
ln -s 1.9.3-p448 1.9
ln -s 2.0.0-p247 2.0.0
ln -s 2.0.0-p247 2.0

最終目標は、各プロジェクトに、use ruby 1.9.3のような分かりやすい構文を含む.envrcファイルがあり、プロジェクトの正しいrubyのバージョンを選択できるようにすることです。

このため、direnvの標準ライブラリで使えるコマンドを使います。 また、~/.config/direnv/direnvrcファイルで少し拡張します。

以下を~/.config/direnv/direnvrcファイルに追加してください(ファイルが存在しないときは作らなければなりません)。

# 使い方:use ruby <バージョン>
#
# 指定されたrubyのバージョンを環境に読み込みます
#
use_ruby() {
  local ruby_dir=$HOME/.rubies/$1
  load_prefix $ruby_dir
  layout ruby
}

以上です。 これで、プロジェクトでdirenv edit .を走らせたり、ファイルにuse ruby 1.9.3use ruby 2.0を追加したりして、direnvにより、プロジェクトのフォルダに入ったときに正しいrubyのバージョンが選択されるようにできます。

少し説明

最後の部分は多分もう少し説明が必要です。 標準ライブラリの一部のコマンドを活用しており、これらはenvrcの実行の文脈で使えます。

useはコマンドの発出器で、use ナントカ カントカの領域特化言語を構築するためだけにあります。 これにより、use ruby <バージョン>use_ruby <バージョン>に読み替えます。

load_prefixにより、環境にいくつかのものが追加されます。 特に、<prefix>/binがPATHに追加されます。 こうすることで、特定のrubyが使えるようになります。

また最後に、layout rubyuseに似ており、layout_ruby関数呼び出しに読み替えます。 これは、一般的なプロジェクトの配置を記述するために使います。 標準ライブラリでは、rubyの配置で(GEM_HOME環境変数により)rubygemsを構成し、プロジェクトルート配下の .direnv/ruby/RUBY_VERSION フォルダに全てのgemがインストールされます。 rvmのgemsetと少し似ていますが、そちらはプロジェクトのフォルダ内にある点が異なります。 また、bundlerを構成して、.direnv/bin フォルダにラッパーのシンボリックリンクをインストールします。 これにより、毎回bundle execでrubyプログラムを前置する代わりに、直接コマンドを呼び出せます。

結論

ここまで見てきたように、この手法はrubyに限定されません。 ~/.pythons配下に様々なバージョンのpythonをインストールし、~/.direnvrcuse_pythonを定義することができるでしょう。 perl、phpなども同様です。 これはdirenvの良い点であり、単一の言語に制限されないのです。

実際のところ、プロジェクトフォルダに入ったとき、全てのプロジェクトの依存関係があると素晴らしくないですか? rubyのバージョンだけでなく、使いたいredisやmysqlやその他諸々の厳密なバージョンを、VMを開始させることなく使えるといいですよね。 筆者はこれが確実に可能であると考えており、それにはNixパッケージ管理のようなものを使います。 そちらについては将来別の記事で見ていく必要があると考えています。