けんごのお屋敷

2014-01-24

spring と direnv を使って Rails と rspec を高速起動。快適開発はじめる

spring は最近流行ってるので、既に知ってる方もいると思いますが Rails のプリローダーです。

Rails を使ってる人だったら bundle exec rails console とか bundle exec rails generate model user とか bundle exec rake routes とか、便利コマンドにお世話になることも多いと思います。

でも Rails ってとても巨大なフレームワークなので、コマンド一つ起動するにも Rails の資産が全部ロードされて結構な時間がかかります。なので Rails をあらかじめバックグラウンドで起動しておくことによって、コマンドの起動時間を大幅に短縮してくれるのが spring です。

前は Gemfile には書かずにシステムに gem コマンドでインストールして spring rake routes とかやってて、コマンドの前に spring と書かないといけないのダルかったのですが、公式のドキュメントを読んでいると最近はまた便利になってるみたいです。

github の README では Rails 4 と Rail 3.2 が対象となっていますが、この記事は Rails 4 前提で書いています。

spring のインストール

最新の spring は Gemfile に書きます。

group :development, :test do
  gem 'spring'
end

$ bundle install
$ bundle exec spring binstub --all

これで spring が使えるようになります。この時 bin/spring というファイルが出来ており、また bin/rakebin/rails の先頭に以下のような行が追加されています。

begin
  load File.expand_path("../spring", __FILE__)
rescue LoadError
end

これで spring をロードするみたいで、ただし spring がない環境でも問題ないように spring が存在しなければ例外を握りつぶして本来のコマンド起動に進むようです。

spring の使い方

bundle exec で実行せずに bin/ 以下のコマンドから実行します。つまり

$ bin/rake routes

とします。初回起動の時だけ Rails アプリケーションがロードされるのでいつもと同じように時間はかかりますが 2 回目以降はロードされたアプリケーションが利用されるので、起動時間が劇的に改善されています。

1 回目

$ time bin/rake routes
...
bin/rake routes  0.11s user 0.06s system 3% cpu 5.009 total

2 回目

$ time bin/rake routes
...
bin/rake routes  0.11s user 0.05s system 26% cpu 0.599 total

1 回目は 5 秒かかっていますが 2 回目は 0.5 秒になっています。

また bin/spring status を実行すると現在の spring の起動状況を確認できます。

$ bin/spring status
Spring is running:

2507 spring server | web_app | started 8 mins ago
2508 spring app    | web_app | started 8 mins ago | development mode

起動している spring は Rails に再起動が必要なファイル(例えば config/application.rb など)が変更されると、それを検知して自動的に再起動する仕組みになっています。起動ファイルの読み込みに関しては気にする必要はないので、とても便利です。

direnv のインストール

これで各コマンドの起動が早くなって嬉しいのですが、どのコマンドも最初に bin/ を入力しないといけないので、まだダルさは残ってます。Rails の bin/ ディレクトリを PATH に追加すればいいのですが、その Rails のプロジェクト外ではそのパスは不要なのでむやみに追加するのもはばかられます。

そこで spring の README でも推していますが direnv の登場です。

これは、パス毎に異なる環境変数をロードすることができるもので、これを使えば spring 入りの Rails プロジェクトのディレクトリに移動した時は PATH に Rails の bin/ を追加して、そのディレクトリから出たら PATH は元の値に戻る、というような挙動をさせることが出来ます。

Mac の場合 Homebrew を使えば簡単にインストールできます。

$ brew install direnv

※Homebrew のバージョンが少し古いと、一見インストールがうまくいったように見えて実は足りないコマンドがあったりするので、インストールしてもうまく動かない場合は brew update をしてからもう一度インストールしてみるとよいかもしれません。

インストールがうまくいったら ~/.bashrc もしくは ~/.zshrc

eval "$(direnv hook bash)" # bash の場合
eval "$(direnv hook zsh)"  # zsh  の場合

という行を追加してあげれば完了です。

direnv の使い方

spring 入りの Rails プロジェクトのディレクトリ内で

$ direnv edit .

# ※EDITOR環境変数が指定されていない場合はエラーになります。
#   以下のように環境変数を指定してコマンドを実行してもOK。
$ EDITOR=vim direnv edit .

とします。すると EDITOR 環境変数に指定されたエディタが起動しますので、そこに

export PATH=$PWD/bin:$PATH

と入力して保存して終了すると、ディレクトリ内に .envrc というファイルができます。これで準備完了です。.envrc があるディレクトリに入ると自動的に Rails の bin/PATH に追加されるので

$ rake routes

だけでコマンドが起動します。高速に。

rspec のテストも高速に起動させる

rspec のテストも spring を使って高速に起動させることができます。そのためにはまず gem が必要で Gemfile に spring-commands-rspec を追加します。

group :development, :test do
  gem 'spring'
  gem 'spring-commands-rspec'
end

$ bundle install
$ spring binstub rspec

こうすることで bin/ ディレクトリ以下に rspec というファイルができあがります。これで準備完了。テストを起動してみましょう。1 回目はいつもと同じように起動に時間がかかりますが 2 回目以降は起動が早くなっていると思います。

$ rspec spec/

何度も実行するコマンドの実行時間がここまで減ると開発時のストレスはかなり減ります。spring 一度ためしてみてはどうでしょうか。

  • このエントリーをはてなブックマークに追加