ライブラリを使う時、バージョンが合わなくてうまく動かないという問題は、Ruby
に限らず、どのプログラミング言語でも常に悩みの種である。特にDepedencyの多いライブラリをインストール/インクルードするときは、大体この問題で躓く。C++
とかでGUI関係のライブラリを入れるときは何度も挫折したし、特に、進化が速く変更の多いPerl
,PHP
をはじめとしたスクリプト言語では普通にそういう問題に出くわす。
もちろんRuby
もその例外ではないのだが、より個人がライブラリ(gem)を作って、githubなどに上げ、公開していくという文化がある割に、あまりこの問題に悩まされないので、Ruby(on Rails)
は比較的うまくやっていると思う。
これは、Bundler
というツール自体の功績でもあるけれど、ライブラリを作る個人個人が、ちゃんと一定の規則に従ってバージョン付けして、依存関係を正しくGemfile
に書くという文化によるものが大きいと思う。なので、Bundler
を支える文化のセマンティック・バージョニングと、Gemfile
の書き方について紹介しようと思う。
今回は、AdventCalendarということで、あんまりRubyを使わない人にも参考になるテーマで書いてみたつもり。
他言語プログラマでも、特に、自分でライブラリを作ってみようかなと思っている人は絶対に知っておくべき。
Semantic Versioning (バージョン付けの規則)
バージョンには付け方があり、基本的にはこの法則に従うべきというガイドラインが存在する。
ちゃんと意味のあるバージョン付けをしましょうということなのだが、それが、Semantic Versioningという名前で以下のURLで公開されている。
http://semver.org/
http://shijimiii.info/technical-memo/semver/ (日本語訳)
ここでは、3.2.8
のように、バージョンを常に3つの数字を.
で区切った方法(X.Y.Z
形式)で、指定する方法のみ説明する。なお、上のURLには1.0.0-alpha.1
や1.3.7+build.11.e0f985a
などのより細かい規則も載っている。
Semantic Versioningの大原則
まず、大原則として以下のルールに則る。
公開APIを定め、それを基にバージョンを付ける。
Semantic Versioningの詳細ルール
あとは、3桁それぞれに意味を持たせ、以下のルールに従ってバージョン付けする。
- すべての公開される変更でバージョンを上げる
- 3つの数字
X.Y.Z
の意味はそれぞれMajor.Minor.Patch
-
Major
をあげるときは後方互換のない変更 - 新しいAPIの公開など
-
Minor
をあげるときは後方互換のある変更 - APIの追加、サポートを外そうとしているAPIに警告を出すなど
-
Patch
をあげるときはバグ修正 - バグ修正の定義は、正しくない挙動を直すこと
- 安定した公式APIが定まるまでは、
0.y.z
形式にしておき、この状況では例外的にいつAPIを変えても良い
ちなみにバージョンは少数ではないので、1.10
と1.9
は1.10
の方が新しいバージョンである。
具体例
バージョン付けの例としては、以下のような流れになる。
0.0.1 # Initial Version
0.0.2
0.1.0 # 0.0.2と比べて機能が大きく変わった。
1.0.0 # 多分Stableであろう、公式APIを定めた!
1.0.1
1.0.2
1.0.3
…
1.0.9
1.0.10
1.0.11
…
1.0.17 # バグだらけでいろいろ修正
1.1.0 # 追加APIを導入。ついでにバグも修正(Minorをあげるのと同時にバグ修正してもOK)
2.0.0 # 過去のしがらみを断ち切り、リニューアルしたAPIを公開
GemfileでのVersion指定の仕方
例えばhoge
という名前のgemがあったとする
安全に今のバージョンのみ使いたい場合
gem "hoge", "2.1.8" # 2.1.8のみ使う
今後のバグ修正のみ受け入れたい場合
基本は、後方互換のある修正はすべて受け入れればよいので数字を2つだけ書いて指定する。
gem "hoge", "~> 2.1" # 2.1.0以上3.0.0未満の最新のものを使用
例えばdevise
などの大き目のgemだったり、なんだかんだでバグ修正以外の機能追加が入ると動かなくなりそうというようなものは数字3つで指定しておく。ちゃんとガイドラインにしたがって運用されていて、公開APIが変わってなくても、推奨されるディレクトリ構成だったり、設定の仕方だったりが変わるというのもありえる。
gem "hoge", "~> 2.1.8" # 2.1.8以上2.2.0未満の最新のものを使用
今後の変更は全て受け入れ最新に追従したい場合
基本は、以下のように何も指定しないでOK
gem "hoge"
公開するgemなどを作っていて、見知らぬユーザーの環境に古いhoge
gemが入っていると困るなどという場合は以下のように>=
を使う。
gem "hoge", ">= 2.1.3" # 2.1.3以上の最新のものを使う
2.1.3
の部分は頑張って自分の書いたものがhoge
gemのどのバージョンからなら動くかを調べて埋める。">= 2.1"
かもしれないし、">= 1"
かもしれない。
参照