MacでRubyの起動が遅すぎたのを修正した話

仕事とかの関係でいい加減Ruby on Railsを勉強しないといけない感に駆られたので
MacにRubyを導入したのですが、起動が遅くてイライラしたのを修正したので残しておきます。
※RubyとかRailsのバージョンが古いのは個人的理由です。最新やりたいよって方は別の記事を参考にすることをおすすめします。
ちなみに下記環境下でのお話です。
新しいバージョンだと修正されているかもしれません。

* Mac OS Sierra
* Ruby 2.3.1
* Rails 5.0.2

~~注１：すでに私の環境下ではGemがたくさんインストールされているから遅くなっているのかもしれません（特に容量が大きいgemが原因みたい？）~~
→rbenv init内のrbenv rehashが重い
→rbenv-gemsetをアンインストールしたらrbenv rehash内で呼ばれなくなって一気に早くなった

# MacだとデフォルトRubyのGemが入らない
MacにはデフォルトでRubyが入っていますが
OS El Capitan以降からセキュリティ機能が強化されて
普通にgem installでパッケージをインストールしようとすると
Permission Deniedエラーでインストールできません。

端的にいうと/usr以外のルート内のフォルダに対して管理者権限（sudo）が必要になります。
[System Integrity Protection](https://developer.apple.com/library/content/releasenotes/MacOSX/WhatsNewInOSX/Articles/MacOSX10_11.html)

デフォルトのRubyでgem installのコマンドを行うと管理者権限が必要なフォルダ領域にインストールしようとしてPermission Deniedで失敗します。
System Integrity Protectionを解除するという方法も存在はするのですがセキュリティ的な観点からおすすめできません。
回避するにはrbenvというRubyのバージョン管理ツール経由でそれぞれのRubyをインストールし、/usr以下の領域に対してgem installします。
詳細は下記を参考にしてください
[gem installでpermission deniedされました](http://qiita.com/tokimari/items/feda1ed61f2d8b5b317c)

# rbenvの起動が遅いのをなんとかする
Macで開発しているとデフォルトで古いバージョンのRubyが入っています。
rbenv経由でインストールしているRubyを有効にするために

.bash_profileに下記コマンドを書くことが一般的だと思います。

```bash
eval "$(rbenv init -)"
```

rbenvの初期化処理は重いです。
原因はrbenv init内のスクリプトで定義されている
rbenv rehashの処理に時間がかかるようです。
（rbenv-gemsetがインストールされている場合はさらに時間がかかるようです）

```
$ time rbenv rehash

real    0m1.841s
user    0m0.085s
sys 0m0.044s
```

実はrbenv rehashは毎回実行する必要がないため、rbenvの初期化処理を修正します。
参考：[rbenv init が重い問題に対する対処法](http://mobileapplication.blog.fc2.com/blog-entry-21.html)

* rbenv initを書き出す

```
echo "$(rbenv init -)" > ~/.rbenv_init
```

* rehashをコメントアウト

```bash
export PATH="/Users/（ユーザ名）/.rbenv/shims:${PATH}"
export RBENV_SHELL=bash
source '/usr/local/Cellar/rbenv/1.1.0/libexec/../completions/rbenv.bash'
#command rbenv rehash 2>/dev/null
rbenv() {
  local command
  command="$1"
  if [ "$#" -gt 0 ]; then
    shift
  fi

  case "$command" in
  rehash|shell)
    eval "$(rbenv "sh-$command" "$@")";;
  *)
    command rbenv "$command" "$@";;
  esac
}
```

* rbenv initの代わりに修正済みのものを呼び出し

```bash
# eval "$(rbenv init -)"
source ~/.rbenv_init
```

補足：
[rbenv rehashが何をやっているか](http://dqn.sakusakutto.jp/2014/02/rbenv_rehash_what_it_does.html)

端的にいうと「~/.rbenv/versions/2.x.y/bin/ 以下に置いてあるコマンド群を ~/.rbenv/shims/以下に置いて使えるようにする」

rbenv rehashは
gem installで追加したパッケージのコマンドを使えるようにする（コマンドのパスを通す）
ということをやっているので通常（ターミナルを開く場合等）は毎回コピーする必要はないはずです。
（初回もしくはgem installした際で十分のはずです）

# rbenv経由のrubyコマンドを実行すると時間がかかる

* MacデフォルトのRubyは早い

```bash
$ time /usr/bin/ruby -e "puts 1"
1

real	0m0.412s
user	0m0.049s
sys	0m0.020s
```

* rbenv 経由の ruby は遅い

rbenvのRubyインストール済みで・・・

```bash
$which ruby
/Users/（ユーザ名）/.rbenv/shims/ruby
$time ruby -e "puts 1"

real    0m2.309s <-- むぅ・・・？
user    0m0.131s
sys 0m0.067s
```

rbenv内の現在設定されているRubyバージョンを探しにいくため時間がかかっているようです。
（rbenv-gemsetがインストールされている場合はさらに時間がかかるようです。）

* rbenv のRubyをバージョン指定して直接叩くと速い

```bash
$time /Users/（ユーザ名）/.rbenv/versions/2.3.1/bin/ruby -e "puts 1"
1

real	0m0.278s
user	0m0.070s
sys	0m0.020s
```

参考：[rbenvのruby が遅いので何とかする](http://takuya-1st.hatenablog.jp/entry/2015/01/08/194932)
上記参考だと色々設定いじってますが、
手っ取り早くやるには固定してしまったほうが早いので自分はrbenvのrubyのバージョンを固定しました。
具体的には.bash_profileにaliasを作成します。

```bash
alias ruby='/Users/(ユーザ名)/.rbenv/versions/2.3.1/bin/ruby'
```

保存後、sourceコマンドで適用

```bash
$source ~/.bash_profile
$time ruby -e "puts 1"
1

real	0m0.256s <-- 早い
user	0m0.063s
sys	0m0.020s
```