モテカワるびいすとのための rbenv 入門
はじめに
こんにちは。嫌われエンジニアの西村(@Sixeight)です。
さいきん Kyoto.rb というコミュニティを始めました。
どうぞよろしくお願いします。
今日はさいきん巷で話題だった(乗り遅れた感ありますね) rbenv について取り上げたいと思います。
弊社ではまだRVMが主流なのですが、アルバイトの若者をたぶらかして少しずつシェアを増やしています。
rbenv ってなに
https://github.com/sstephenson/rbenv
インストール済の複数のRubyをよしなに切り替えてくれるべんりツールです。
37signalsのsstephensonことSam Stephensonさんによるプロダクトです。
他にもかっこ良いプロダクトを書きまくられています。
最初にREADME.mdから抜粋。
rbenvがしてくれること
rbenvは3つのことを提供してくれます。
- ユーザ毎に使用するRubyのバージョンを変更できます -> たとえば 1.9.3 と 2.0.0-dev をインストールしていると、これらを好きな時に切り替えて使用できます
- プロジェクト毎にRubyのバージョンをを指定出来ます -> .rbenv-version というファイルを読み取って特定のディレクトリ以下のRubyのバージョンを指定できます。
- 環境変数によってRubyのバージョンを指定出来ます -> RBENV_VERSION を指定しておくとその環境変数が有効な範囲でだけRubyのバージョンを指定できます。
rbenv がしてくれないこと
rbenvはRVMと比較して以下のことはしないとしています。 RVMの問題点を改善するために産まれた経緯からもこの“しないこと"は重要です。
- シェルに変なスクリプトをロードする必要はありません -> rbenvが採用しているShimを使った方法では
$PATH
にディレクトリを追加するだけで動作します。 - シェルのコマンドを上書きしません -> たとえば
cd
とか。これは大変危険だし、バグの温床になります - 設定ファイルを必要としません -> 必要なのはRubyのバージョン番号だけ!
- Rubyのインストールはしません ->
rvm install 1.9.3
みたいなことは出来ません。rbenvがやることはあくまでインストールされたRubyのバージョンの切り替えです。代りにruby-buildを使うことでrvm install
と同様のことを実現しています。 - Gemsetの管理はしません -> BundlerはGemsetより良いGemの管理方法なので、Bundlerを使うべき。まだBundlerを導入していないプロジェクト向きにrbenv-gemsetもあります。
- 相性が良くないべつのRubyライブラリを変更する必要はありません -> CapistranoでRVMを使うためには結構たいへんだけど、rbenvではそんなことは起りません。
- バージョンを切り替えるときに警告を出しません -> RVMのように任意のコードを実行できるようにはなってなくて、バージョン番号しか指定しないので、そもそも信頼する必要がありません。
インストール方法
ふつうのプログラマのみなさんはMacユーザだと思いますので、当然のようにHomeBrewを使います。
RVMのアンインストール
RVMをインストールされている場合は競合して問題が起きないようアンインストールしておく必要があります。 以下のコマンドをタイプしてRVMをアンインストール後、~/zshrcなどに書いていたRVM関連のスクリプトを削除してください。
$ rvm seppuku
rbenv と ruby-build のインストール
rbenv本体とRubyをインストールするのに使用するruby-buildをインストールします。 Rubyは手動でコンパイルするという方はrbenvのみどうぞ。
$ brew install rbenv ruby-build $ echo 'eval "$(rbenv init -)"' >> ~/.zshenv
Bashの方は~/.zshenvの代りに~/.bash_profileに追記してください。
以上です。簡単でしょ。
Ruby 1.9.3-p194 を入れてみる
これでRubyを管理する準備が整いました。
さっそく1.9.3をインストールしてみましょう。
HomeBrewでインストールしたReadlineとOpenSSLをリンクするように指定しています。
$ brew install readline openssl $ brew link readline $ brew link openssl $ CONFIGURE_OPTS="--with-readline-dir=/usr/local --with-openssl-dir=/usr/local" rbenv install 1.9.3-p194
以上でインストール完了です。rbenv versions
と入力してちゃんとインストール出来ているか確認してみてください。
私の環境では以下のように表示されました。(他のバージョンもインストールしています)
$ rbenv versions 1.8.7-p358 1.9.2-p290 * 1.9.3-p194 (set by /Users/tomohiro/.rbenv/version) 2.0.0-dev
via: https://gist.github.com/50aa2ed60c2cec3d49d3
Rubyを切り替える
rbenvを使ってRubyを切り替える方法は3つあります。(rbenvがしてくれること参照)
- 通常使用するRubyのバージョンを指定する(global)
- プロジェクト毎(特定のディレクトリ以下)で使用するRubyのバージョンを指定する(local)
- そのシェル内でのみ使用するRubyのバージョンを指定する(shell)
通常使用するRubyのバージョンを指定する(global)
広く使用するRubyのバージョンを指定します。基本的にはここで指定したバージョンのRubyが使用されることになります。
$ rbenv global 1.9.3-p194
ここで指定したバージョンは~/.rbenv/version
ファイルに書き込まれて保持されます。
このバージョンは後述する、.rbenv-version
か$RBENV_VERSION
によって上書きされます。
プロジェクト毎(特定のディレクトリ以下)で使用するRubyのバージョンを指定する(local)
あるディレクトリ以下にいるときのRubyのバージョンを指定するにはrbenv local
を使用します。
$ rbenv local 1.9.3-p194
このコマンドを実行したディレクトリに.rbenv-version
というファイルが作成され、そこにバージョン番号が記述されます。
今後、このファイルがあるディレクトリ以下に移動すると、ファイルに記述されたバージョンのRubyが使用されることになります。
また、このバージョンは$RBENV_VERSION
によって上書きされます。
そのシェル内でのみ使用するRubyのバージョンを指定する(shell)
実行中のシェル内でのみ有効なRubyのバージョンを指定するにrbenv shell
を使用します。
$ rbenv shell 1.9.3-p194
これによって、RBENV_VERSION
という環境変数がセットされ、global/localどちらの指定も上書きすること出来ます。
設定した環境変数をリセットするには--unset
オプションを使用します。
$ rbenv shell --unset
仕組み
さて、使い方は分かりましたでしょうか。次は仕組みをみていこうと思います。 詳しい解説はsugyanさんのrbenvの切り替えの仕組み…と、他言語での実験を見て頂くとして、ざっくり概要をまとめたいと思います。
HomeBrewでインストールしたrbenvのユーザ側のディレクトリ構成は以下のようになっています。
$ tree -L 1 .rbenv .rbenv ├── shims ├── version └── versions
rbenvではRuby関連の実行ファイルを全て~/.rbenv/shims
以下のラッパスクリプトを経由して実行します。
~/.rbenv/shims
以下にはインストールしている全てのバージョンのRubyに関連する実行ファイルのラッパスクリプトが配置されています。
(中身は全て同じです)
当然Rubyインタプリタ自体もここに収められており、which ruby
の結果は私の環境の場合/Users/tomohiro/.rbenv/shims/ruby
となります。
このラッパスクリプトが実行されると、rbenvはrbenv-which
を使って実際の実行ファイルの場所を探しに行きます。rbenv-which
は~/.rbenv/versions/#{rbenv-version}/bin
以下を探索します。
$ tree -L 2 .rbenv/versions .rbenv/versions ├── 1.8.7-p358 │ ├── bin │ ├── lib │ └── share ├── 1.9.2-p290 │ ├── bin │ ├── include │ ├── lib │ └── share ├── 1.9.3-p194 │ ├── bin │ ├── include │ ├── lib │ └── share └── 2.0.0-dev ├── bin ├── include ├── lib └── share
ここで言うrbenv-version
は、rbenv version
の実態であり現在使用しているRubyのバージョンを返してくれます。
つまり、1.9.3-p194を使用しているときは~/.rbenv/versions/1.9.3-p194/bin/ruby
が実行されて、2.0.0-devを使用しているときは~/.rbenv/versions/2.0.0-dev/bin/ruby
が使用される仕組みです。
単純ですよね。
これはインストールしているGemの実行ファイルについても同様で、たとえばBundlerなら~/.rbenv/versions/#{rvenv-version}/bin/bundler
が実行されます。
これはインストールのときにした、rbenv init -
によって、$PATH
に~/.rbenv/shims
が追加されているため実現できています。
つまり
思い切りはしょってまとめると以下のようになります。
ruby
を実行すると~/.rbenv/shims/ruby
が実行される~/.rbenv/shims/ruby
は実際の実行ファイルを探して実行しようとする- 実際のファイルは
~/.rbenv/versions/#{rbenv-version}/bin
に配置されていることが分っているためrbenv-version
を決定する - 実行ファイルが見つかったので実行する
rvenv-version
は3ステップでバージョンを確定します。
$RBENV_VERSION
が設定されているか確認する- 設定されていなければ、
.rbenv-version
が存在しているか確認する - 存在していなければ
~/.rbenv/version
を見る
Shimは誰が作るか
大変重要な役割をしているShimたちは一体誰が作るのでしょうか。答はrbenv-rehash
です。
そう、あの毎回実行しなくてはならなくて面倒くさいrbenv rehash
の実体です。
これを実行すると、~/.rbenv/versions/*bin/
以下を探索して~/.rbenv/shims/
以下のShimを再生成してくれます。
とてもめんどうくさいのですがこれを怠るとインストールしたべんりツールが実行できなくなってしまうのです。
(理由を知ってもそれでも面倒だと思うかたはgem i rbenv-rehash
しておくとしあわせになれるようです)
ちなみに今まで上げてきたrbenv-*
というスクリプトはHomeBrewでインストールした場合は/usr/local/Cellar/rbenv/#{version}/libexec
以下にインストールされています。
$ ls /usr/local/Cellar/rbenv/0.3.0/libexec rbenv rbenv-exec rbenv-hooks rbenv-prefix rbenv-sh-shell rbenv-version-file rbenv-version-name rbenv-whence rbenv-commands rbenv-global rbenv-init rbenv-rehash rbenv-shims rbenv-version-file-read rbenv-version-origin rbenv-which rbenv-completions rbenv-help rbenv-local rbenv-root rbenv-version rbenv-version-file-write rbenv-versions
ちょっと便利にする
現在のRubyのバージョンはrbenv version
で確認することが出来ますが、私みたいに面倒くさがりな方にはシェルのプロンプトに現在のバージョンを表示しておくことをお勧めします。
Zshの場合は以下のようにして実現します。
まずはバージョンを文字列として返す関数を定義します。
function rbenv_version() { echo -n "${$(rbenv version)%% *}" }
あとはこれを良い感じにプロンプトに表示します。例えば以下のようにすると1.9.3-p194 >
のようなプロンプトを表示できます。
PROMPT='$(rbenv_version) >'
さいごに
rbenvの欠点はrvmに比べてタイプ数が多く左側に集中しているため非常に入力が困難な点です。
一時期はあまりの苦行に耐え切れずにalias rvm=rbenv
などとしていましたが、さすがに気がひけたので最近は入力できるように訓練しています。
貴重なネームスペースを消費しないためにキラキラネームが推奨されているとはいえ、入力しやすい名前をつけるのは重要なことだと思いました。
最後まで読んで頂きありがとうございました。
追記
「rb<tab>
で補完すれば良いのでは???」というご意見を頂きました。
たしかにと思って確認したら、rb<tab>
だとrb[space]
に補完されました。そういえばこれのせいでrbenvとフルで入力することになっていたのでした。
このrbって一体なんだと思って調べると、何にことはない、自分で定義した使ってないaliasでした。
ということ、rbをaliasから削除して、快適に補完できるようにしました。
一緒に働きたい方、絶賛 募集中
京都で開発してみたいというエンジニアの皆さん、ご応募お待ちしています!
技術力を伸ばしたい学生さん、アルバイトも可能なのでご応募お待ちしています!
大阪、滋賀、神戸から通勤実績あり