Bundlerをゆるふわに使っていていたい目にあったお話
今日のハイライト
きっ、聞いてないよ!Bundlerを使って必要なGemをインストールするまではよかったのに、バージョンが違うみたいでそんな動きかたしてないだなんて!
改めましてBundlerとは
RubyのライブラリはRubyGemsというツールでインストールすることができます。名前もルビーだけにGem(宝石)となかなかおしゃれですね。しかし、プロジェクトを他の環境で動かしたいとき、
というのを何かしらの手段で伝えないといけません。何も考えずにやるとすごく面倒で、足りないものがないかヒヤヒヤしますね。間違って他のライブラリをインストールしてしまう単純なうっかりから、バージョン違いで挙動の整合性がとれないくなって「原因不明のバグ」が起きたりもします。機能を追加して必要なライブラリが増えると、その度に報告しなければいけません。とてもめんどくさいですね。
そこでBundlerの出番です。アプリケーションのルートディレクトリにGemfileというファイルを作っておいて、そこに必要なものを書いていけばいいわけです。あとはBundlerさんがGemfileに書かれた必要なライブラリを持ってきてくれる、という寸法です。
さて冒頭に戻りまして
ちなみにBundlerさん、このバージョンのGemを持ってきてねと指定することもできるのですが、私はあまりここをまじめに書いていなかったので今回痛い目を見ました。Gemfile.lockを持ち回らなかった環境でGemのバージョンが違って、「原因不明のエラー」に頭を抱えていたのでした。それほど難しい話ではないのですが、後学のためメモしておきます。
Gemspecについて
今回は特に触れません。なにやら依存性を書いておくファイルらしいよとだけいっておきます。たぶんGemを作る機会があればそのときに覚え直すことになりそう
Gemfileについて
Gemfileは必要なGemをどこから持ってくるかを指定します。
バージョン指定の書き方
決め打ちするならGemの名前の次にバージョンの数字を書いておけばOK。
gem 'rails', '4.0.0'
わかりやすいですね。
比較的よく見る気がする~>はマイナーバージョンは何でもいいよと伝えます。
gem 'devise', '~>3.0.0'
とすると、3.0.0や3.0.1といったバージョンのDeviseがインストールされますが、3.1.0といったバージョンはインストールされません。
このバージョン以上のものがほしいときはこちらを使います。
gem 'rspec', '>=2.8.0'
この場合は2.8.0以上のなるべく新しいバージョンのRSpecがインストールされます。バージョンの上限を制限することもできて、
gem 'sinatra', '< 1.0.0'
としておくと、1.0.0以上のSinatraはインストールされません。ちなみに、以上と未満は組み合わせて指定できます。ドキュメントを見る限りでは、以下とそれより大きいバージョンで指定することはできないみたいです。
Bundlerが今の環境に持ってきたGemが知りたいときは
bundle list
で一覧表示してくれるので、それをもとにバージョンを固定するか、Gemfile.lockも一緒に持っていくかしましょう。
Gemfile.lockって何者?
必要なGemが仔細にまとめて書いてあるファイルです。Gemfileでバージョンを指定しなかったGemのバージョンはここで決め打ちされるようです。BundlerでGemをインストール、アップデートしたときに自動で作られたり書き換えられたりするファイルで、中には人間にとってはあんまりフレンドリーじゃないフォーマットでBundlerが持ってきたGemが書かれています。手で書いてもいいのかもしれませんがあんまり考えたくないですね。
私のところではbundle installすると何度でもよみがえるので、バージョン管理していてマージに失敗すると消される憂き目に遭っています*1。
GemfileとGemfile.lockがあれば、どんな環境でも同じGem使うことができます(なかなか反例が思いつかない程度にはそのはず)。
3兄弟の中で唯一ファイルをバージョン管理するべきか否かという議論が持ち上がるファイルでもあります。