Ruby: GemfileとGemfile.lock究極ガイド(翻訳)
Ruby on Railsの開発者なら、GemfileやGemfile.lockを知らない人はいないでしょう。この2つのファイルはRuby gemをインストールするのに欠かせませんが、仕組みを知らないままでは混乱する可能性もあります。本記事では、Gemfileとは何か、その中に何があるのか、および使い方について解説します。
最初に、デフォルトのRails 7アプリケーションを作成し、それからGemfileの各行を調べて意味を理解していきましょう。
新規作成したアプリのディレクトリには、GemfileとGemfile.lockがあるのがわかります。
# 新規作成したGemfile
source "https://rubygems.org"
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
ruby "3.1.0"
gem "rails", "~> 7.0.3", ">= 7.0.3.1"
gem "sprockets-rails"
gem "sqlite3", "~> 1.4"
gem "puma", "~> 5.0"
gem "importmap-rails"
gem "turbo-rails"
gem "stimulus-rails"
gem "jbuilder"
gem "redis", "~> 4.0"
gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ]
gem "bootsnap", require: false
group :development, :test do
gem "debug", platforms: %i[ mri mingw x64_mingw ]
end
group :development do
gem "web-console"
end
まずは最も基本的な疑問を解消しましょう。
🔗 Gemfileってそもそも何なの?
Gemfileを一言で言うと、アプリケーションで必要なすべてのgemのリストを含むファイルです。bundle install
を実行すると、Bundlerがそれらのgemを探索してインストールします。
たとえば上のGemfileにgem "rails", "~> 7.0.3", ">= 7.0.3.1"
とあるのは、このアプリケーションでRailsのgemを使うという意味です。
🔗 Gemfileのgemはどこから来るの?
gemがどこから来るかを理解するために、新たに生成したGemfileの最初の2行を詳しく調べてみましょう。
source "https://rubygems.org"
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
source
キーワードは「グローバルソース」と呼ばれています。1個のGemfileにつきグローバルソースは1つだけです。ほとんどの場合、source
には "https://rubygems.org" が使われますが、たとえば私たちが独自のGemfury
アカウントを使っている場合は以下のような別のsource
にすることもあります。
source "https://user:password@gems.example.com"
2行目のgit_source
メソッドは、Gitリポジトリにあるgemを使うよう指示します。組み込みの:github
というGitソースはひとつの例ですが、独自のGitソースを作って使うことも可能です。
認証gemとして有名なdevise
gemがアプリケーションで必要になり、このgemをGitHubリポジトリからインストールすることに決めたとしましょう。この場合、以下のさまざまな指定方法が使えます。
- その1: 最新バージョンのgemを探索してインストールする(GitHubからgemをインストールするときの最も一般的な方法)。
gem "devise", github: "plataformatec/devise"
- その2: 特定のブランチを指定してgemをインストールする
gem "devise", github: "plataformatec/devise", branch: "4-stable"
- その3: 特定のタグを指定してgemをインストールする
gem "devise", github: "plataformatec/devise", tag: "v4.1.0"
- その4: 特定のコミットを指定してgemをインストールする
gem "devise", github: "plataformatec/devise", ref: "d4bf52bdfd652cc1d87fa5800a04b288a81fd787"
追伸: Bundlerでは、:github
以外に:gist
や:bitbucket
もgit_sources
の組み込みとして指定できます。ただし独自のgit_sources
はいつでも作成できます。
🔗 Gemfile内でRubyのバージョンを指定する方法は?
ruby "3.1.0"
Gemfileに上の行があると、BundlerはRuby 3.1.0を使います。Rubyバージョンが指定されていない場合は、デフォルトのバージョンのRubyを使います。実行中のRubyバージョンがGemfile内で指定されているRubyバージョンと合っていない場合は、Bundlerで例外が発生します。
Your Ruby version is 2.7.6, but your Gemfile specified 3.1.0
ローカルのRubyバージョンが2.7.6で、Gemfileで指定されているRubyバージョンが3.1.0の場合は例外が発生します。さらに:engine
オプションや:engine_versions
オプションを使うと、使いたいRubyエンジンやバージョンを指定できます。
ruby "3.1.0", engine: "jruby", engine_version: '9.1.1.0'
🔗 gemの設定オプションにはどんなものがあるの?
大小さまざまな設定オプションを使ってgemの属性を細かく指定できます。
もう一度Gemfileを見てみましょう。
gem "rails", "~> 7.0.3", ">= 7.0.3.1"
gem "sprockets-rails"
gem "sqlite3", "~> 1.4"
gem "puma", "~> 5.0"
gem "importmap-rails"
gem "turbo-rails"
gem "stimulus-rails"
gem "jbuilder"
gem "redis", "~> 4.0"
gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ]
gem "bootsnap", require: false
ここではdevise
gemをインストールする必要があるとします。ここで誰しもすぐに気がつくのは、Gemfileにgemを追加する方法が1種類ではなく、たくさんあることです。たいていのgemにはバージョンが複数あり、動作するプラットフォームもさまざまです。また、gemのバージョン指定方法もいろいろあることに気づきます。
=
- 指定のバージョンに等しい(デフォルト)
!=
- 指定のバージョンに等しくない
>
- 指定のバージョンより大きい
<
- 指定のバージョンより小さい
>=
- 指定のバージョンと等しいか大きい
<=
- 指定のバージョンと等しいか小さい
~>
- 指定のバージョンと等しいか大きい(悲観的な比較)
🔗 =
演算子
最もシンプルなgemバージョン指定方法は、=
演算子を使うことです。
gem "devise", "= 4.0.0"
上の場合は、devise
gem 4.0.0だけをインストールします。バージョンを何も指定しない場合は、利用可能なgemバージョンのうち最新のものをインストールします。
🔗 !=
演算子
バージョン3.1.1以外のdevise
gemをインストールするとしましょう(このバージョンがアプリでサポートされていないなどの理由で)。そういうときは以下のようにも書けます。
gem "devise", "!= 3.1.1"
上の場合は、3.1.1でない最新のdevise
gemをインストールします。
🔗 >
と<
演算子
devise
gemのバージョンのうち、3.1.0より大きく4.1.0より小さいバージョンだけをインストールしたい場合は、以下のように書きます。
gem "devise", "> 3.1.0", "< 4.1.0"
🔗 >=
と<=
演算子
devise
gemのバージョンのうち、3.1.0以上かつ4.1.0以下のバージョンだけをインストールしたい場合は、以下のように書きます。
gem "devise", ">= 3.1.0", "<= 4.1.0"
🔗 ~>
演算子
たとえばアプリケーションのコードベースを壊さずにdevise gemの今後のバージョンでも動くようにしたいとしましょう。これを確実に行う唯一の方法は、後方互換性のあるgemバージョンだけをインストールすることです。つまり、システムにdevise 3.1.0がインストールされているのであれば、最新のdevise 4.1.0をインストールするよりも、devise 3.1.1をインストールする方がアプリケーションが壊れにくくなります。
インストールできるgemバージョンを特定の範囲のみに制限したい場合は、悲観的バージョン演算子~>
を利用できます。
gem "devise", "~> 3.1" # これは">= 3.1.0", "< 4.0.0"と同じ
~>
演算子で指定するバージョンの桁数を3.1
から以下のように3.1.0
に増やすと、バージョンの範囲を狭められます。
gem "devise", "~> 3.1.0" # これは">= 3.1.0", "< 3.2.0"と同じ
ところで、これらのバージョン指定子について、誰もが一度はこんな重大な疑問を抱いたことがあるはずです。
🔗 gemはバージョン指定なしで追加すべきなの?
バージョン指定子なしでgemを追加するのはバッドプラクティスとみなされています。バージョン指定子なしでgemを追加すると、実は暗黙で= 0.0.0
というバージョン指定子をつけるのと同じになります。
gem "devise" # => gem "devise", "= 0.0.0"
これは現在のアプリケーションでは問題なく動くかもしれませんが、今後アプリケーションをアップグレードするとgemの互換性が失われてアプリケーションが壊れる可能性があるかもしれません。つまり、安全のためにはバージョン指定子を常に指定しておくべきということになります。
🔗 require: false
って何?
Gemfileを開くと、たとえばbootsnap gemに以下のようなrequire: false
というオプションが追加されていたりします。
gem "bootsnap", require: false
これは、bundle install
を実行した時点ではbootsnap gemをインストールするだけにとどめ、require
はしないでおくよう指示しています。require
を実行すると、アプリケーションが起動するときにすべての関連gemファイルが読み込まれます。
require: false
オプションは、アプリケーションと直接関係ないgemをインストールする場合に便利です。コード品質のチェックやメトリクス計測に使うgemをたくさんインストールすることがありますが、アプリケーションで直接使わずに開発の利便性を高めるだけのgemにrequire: false
を指定しておけば、必要が生じたときにのみ遅延読み込みされるようになります。
たとえば、bootsnapはconfig/boot.rbファイル内で使われています。つまり、config/boot.rbファイル内では必要に応じてbootsnapを以下のようにrequire
できます。
require "bootsnap/setup"
上のコードはconfig/boot.rbファイル内にあり、ここでbootsnapは遅延読み込みする形でrequire
されています。
🔗 環境を指定してgemをインストールするには?
私たちのGemfileには以下の記述があります。
group :development, :test do
gem "debug", platforms: %i[ mri mingw x64_mingw ]
end
group :development do
gem "web-console"
end
私たちのGemfileには:development
と:test
という2つのグループが追加されていることがわかります。これは、特定の環境でのみ使うgemをインストールするのに役立ちます。
:development
グループ内でインストールしたgemはdevelopment環境でのみ利用できます。:test
や:production
などについても同じ要領で設定できます。
debug gemが必要なのは:development
グループと:test
グループのみで、:production
グループでは必須ではありません。web-console gemが必要なのは:development
グループのみで、:test
や:production
では必須ではありません。
たとえば、development環境とtest環境ではsqlite3 gemを使い、production環境ではPostgreSQLを使いたいとしましょう。これを行うには、以下のようにsqlite3 gemを:development, :test
グループに追加し、PostgreSQLは:production
グループに追加します。
group :development, :test do
gem "sqlite3", "~> 1.4"
end
group :production do
gem "pg", "~> 0.18"
end
ただし、アプリケーションをどの環境で実行しても、システムにはすべてのgemがダウンロード1されることをお忘れなく。つまり、production環境のサーバーでもtest環境用のgemやdevelopment環境用のgemがダウンロードされます。
🔗 プラットフォーム
platforms:
オプションも、gemのグループ化と似たような感じでgemをグループ化しますが、そのgemが利用可能なプラットフォームを指定する点が異なります。
gem "debug", platforms: %i[ mri mingw x64_mingw ]
上のgemは、mri
、mingw
、x64_mingw
プラットフォームで利用できるようになります。
指定できるプラットフォームは以下のとおりです。
ruby
- CRuby(MRI)、Rubinius、TruffleRuby
ただしWindowsは含まない mri
- CRuby(MRI)のみ、
ただしWindowsは含まない mingw
- Windows 32ビット'mingw32'プラットフォーム
(RubyInstallerとも呼ばれます) x64_mingw
- Windows 64ビット'mingw32'プラットフォーム
(RubyInstaller x64とも呼ばれます) rbx
- Rubynius
jruby
- JRuby
truffleruby
- TruffleRuby
mswin
- Windows
訳注
ruby
、mri
、 mswin
、mswin64
、windows
ではバージョン指定も可能です。たとえばRuby 2.3を指定する場合は以下のように書きます。
ruby_23
参考: Bundler: gemfile
🔗 Gemfile.lockって何?
最後はGemfile.lockファイルです。このファイルには、現在インストールされているgemに関するすべての情報が含まれています。
Gemfile.lockは、bundle install
コマンドを実行すると作成されます。Gemfile.lockには、そのアプリケーションで必要なgemの正確なバージョン付きリストが含まれています。
私たちが生成したGemfile.lockファイルの中身を見てみましょう。
GEM
remote: https://rubygems.org/
specs:
rails (7.0.3.1)
actioncable (= 7.0.3.1)
actionmailbox (= 7.0.3.1)
actionmailer (= 7.0.3.1)
actionpack (= 7.0.3.1)
actiontext (= 7.0.3.1)
actionview (= 7.0.3.1)
activejob (= 7.0.3.1)
activemodel (= 7.0.3.1)
activerecord (= 7.0.3.1)
activestorage (= 7.0.3.1)
activesupport (= 7.0.3.1)
bundler (>= 1.15.0)
railties (= 7.0.3.1)
...
PLATFORMS
x86_64-darwin-20
DEPENDENCIES
bootsnap
debug
importmap-rails
jbuilder
puma (~> 5.0)
rails (~> 7.0.3, >= 7.0.3.1)
redis (~> 4.0)
sprockets-rails
sqlite3 (~> 1.4)
stimulus-rails
turbo-rails
tzinfo-data
web-console
RUBY VERSION
ruby 3.1.0p0
BUNDLED WITH
2.3.14
上のGemfile.lockファイルは、以下の4つのセクションに分かれています。
🔗 GEM
GEMセクションには実際にインストールされているgemがあり、以下の2つのパートに分かれています。
remote:
- インストールしたgemの取得元が記述されています。ここでは"https://rubygems.org/"です。
specs:
- インストールされているgemのリストです。Gemfileに記述されているgemよりも数が多いことがわかります。これは、Gemfileに記述されているgemで必要な依存gemもインストールする必要があるためです。
たとえば、rails gemが多くのgemに依存していることがこのセクションを見るとわかります。つまり、これらのgemもインストールする必要があります。
🔗 PLATFORMS
PLATFORMSセクションには、gemを利用可能なプラットフォームのリストがあります。
アプリケーションディレクトリでbundle platform
を実行すると、以下のような出力が得られます。
Your platform is: x86_64-darwin-20
Your app has gems that work on these platforms:
* x86_64-darwin-20
Your Gemfile specifies a Ruby version requirement:
* ruby 3.1.0p0
🔗 DEPENDENCIES
DEPENDENCIESセクションは、そのアプリケーションで現在インストールされている依存gemのリストです。これらのgemは、Gemfile内にあるgemのリストです。
🔗 RUBY VERSION
RUBY VERSIONセクションは、Gemfileで指定されたRubyバージョンです。
RUBY VERSION
ruby 3.1.0p0 # GemfileがRuby 3.1.0p0用であることを示す
🔗 BUNDLED WITH
BUNDLED WITHセクションは、必要なgemを最後にインストールするのに使われたBundlerのバージョンです。
BUNDLED WITH
2.3.14 # Bundler 2.3.14が使われたことを示す
GemfileやBundlerについて詳しくは、以下の公式ドキュメントをどうぞ。
参考: Bundler: gemfile
本記事を読んだ皆さんのGemfileやGemfile.lockの理解が進むことを願っています。
関連記事
- 原文では「install」でしたが、Bundlerのドキュメントに合わせて「ダウンロード」としました。その環境で使わないgemはダウンロードされるだけで、インストールはされません。 ↩
概要
元サイトの許諾を得て翻訳・公開いたします。