Gem,Bundler,Gemfile,Gemfile.lockについて

gem,bundler,Gemfile,Gemfile.lockの違いを整理したいと思います.

RubyGemsとGem

The RubyGems software allows you to easily download, install, and use ruby software packages on your system. The software package is called a “gem” which contains a packaged Ruby application or library.

RubyGemsソフトウェアはRubyのパッケージを簡単にダウンロード,インストール,及び使用をすることができます. パッケージング化されたアプリケーションやライブラリを含んだパッケージをgemと呼びます.

Bundler

Bundler provides a consistent environment for Ruby projects by tracking and installing the exact gems and versions that are needed. Bundlerはプロジェクトで必要とされている特定のGemとバージョンを追跡し,インストールを行うことで一貫した環境を提供します.

  • Bundlerの目的は上記で説明しました.ではbunlderは何をみてプロジェクトで必要とされているgemをインストールするのでしょうか? 答えはGemfileとGemfile.lockです.

Gemfile

  • Gemfileはrailsアプリケーションに使用されているgemを記述したファイルです.具体的には以下のように記述します.
source 'https://rubygems.org'

gem 'rails', '3.2.1'

gem 'sqlite3'

gem 'json'

group :assets do
  gem 'sass-rails',   '~> 3.2.3'
  gem 'coffee-rails', '~> 3.2.1'

  gem 'uglifier', '>= 1.0.3'
end

sourceオプションにはgemをインストールするためのリポジトリを記述します. sourceオプションを指定することによって,gemをどこのリポジトリからインストールするかを指定します. また,例外的にあるgemだけインストールするリポジトリを変更したい場合はに以下のように明示的にsourceオプションを指定します.

source 'https://rubygems.org'
    gem "some_internal_gem", :source => "https://gems.example.com"
end

また,gemのバージョンを指定する場合はpessimistic operator(~>や>=のこと)を使用することが推奨されています.

github.com

pessimistic operator

  • pessimistic operatorを導入することでgemの管理を柔軟に対応することができます. まず,pessimistic operatorは若干癖があるので,簡単に説明します.
  gem 'sass-rails',   '~> 3.2.3'

と記述された場合,Gemfileは'sass-rails'は3.2.3以上3.3以下までのsass-railsのバージョンを使用するということをbundleに伝えます.

  gem 'sass-rails',   '~> 3.2.3.1'

と記述された場合,Gemfileは'sass-rails'は3.2.3.1以上3.2.3.2以下までのsass-railsのバージョンを使用するということをbundleに伝えます.

pessimistic operatorを指定する理由

  • 開発する立場からすると,updateに時間を割きたくありません.
gem "sass", "2.1.8"
gem 'fuga', "3.0.1"

のようにバージョンを指定して記述した場合を例に考えてみましょう. sass version 2.1.8に脆弱性が見つかり,version 2.1.9がリリースされたため,gemのupdateを行う必要があります.gemのバージョンをupdateするにはGemfileを

gem "sass", "2.1.9"
gem 'fuga', "3.0.1"

に書き換え

$ bundle update

を実行します. 次に,fugaに脆弱性が見つかり,3.0.2がリリースされました.そのためsassと同じようにGemfileを書き換え,updateコマンドを実行しました. 開発で使用しているgemが2つなら,人手でなんとか管理できるかもしれません.しかし,通常の開発では数多くのgemを使用して開発を行います.数多くのgemの中で,上記のような手順を踏んでupdateを行っていた場合,開発が全く進みません. pessimistic operatorを使用することで,上記のようなupdate作業に悩まされることはありません.

gem "sass", "~> 2.1.8"
gem 'fuga', "~> 3.0.1"

と記述することで

$ bundle update

コマンド1つでupdateを行うことができます.

ライブラリのupdateに時間をかけたくなければ,バージョンを指定しなければいいじゃないかと思う人もいるかもしれません. それはその通りです.

gem "sass"
gem 'fuga'

のように記述することで,Gemfileを書き換えず,updateコマンド1つでgemをupdateすることができます. しかし,gemのバージョンによっては記述方法が変わる場合があります. python2とpython3でプログラムの記述方式が変わったようにgemでもライブラリのバージョンが大きく変わった場合,そのようなことが起こりえます. 現在のソースコードをセキュリティ的に安全に使いたいやパフォーマンスをよくしたいが,gemのupdateによりソースコードを変更したくないという開発者のわがままな要求を実現できます.

Gemfile.lock

Gemfile.lockはインストールされたgemの特定のバージョンが記述されます. Gemfile.lockはGemfile.lockがないプロジェクト内で,bundle installを実行した場合に生成されます.

GEM
  remote: https://rubygems.org/
  specs:
    actionmailer (3.2.13)
      actionpack (= 3.2.13)
      mail (~> 2.5.3)

ネストはインストールしたgemの依存ライブラリを表しています.gemの開発に使用したgemなどがネストされ記述されています(多分). また,Gemfile.lockがあるプロジェクト内でbundle installを実行した場合は,Gemfile.lockを参照しgemのインストールを行います.

Gemfile.lockの必要性

Gemfile.lockはプロジェクト内で使用しているgemのバージョンを統一するために必要です. pessimistic operatorを使用して,gemのバージョンを指定した場合,bundle installを実行した時期によってインストールされるgemのバージョンが異なります. Gemfile.lockをプロジェクトのリポジトリに含めなければ,チーム内でばらばらのgemのバージョンを使用して作業することになりえます.