Bundlerの原理
もし我々がお勧めするワークフローを知りたいだけで、 原理について特に気にならないのであれば、概要までスキップしていただいても構いません。
- Bundlerの目的と原理
- Bundlerを使用するためのアプリケーションの設定
- バージョン管理のコードを確認
- 他の開発者とアプリケーションを共有する
- 依存性の更新
- Gemfileを変更せずに、Gemを更新
- 概要
- 注釈
Bundlerの目的と原理
始めに、あなたのアプリケーションのルート・ディレクトリのGemfile
と呼ばれるファイルに依存性を宣言します。
これは次のようになります。
source 'https://rubygems.org'
gem 'rails', '4.1.0.rc2'
gem 'rack-cache'
gem 'nokogiri', '~> 1.6.1'
Gemfile
は幾つかの事を主張します。
始めに、BundlerはGemfile
内に宣言されたhttp://rubygems.org
からGemを探すべきと主張しています。
もし、プライベートなGemサーバーからGemを取得する必要がある場合は、
このデフォルトのGem供給元をそれ用に上書きすることが可能です。
次に、幾つかの依存関係を宣言しています。
-
rails
のバージョンは4.1.0.rc2
であること。 -
rack-cache
のバージョンは任意であること。 -
nokogiri
のバージョンは>= 1.6.1
であるが、< 1.7.0
であること。
依存性の宣言をしたら、それらを取得するようにBundlerに指示を出します。
$ bundle install # 省略して bundle とすることも可能です。
Bundlerはrubygems.org
に接続し(他に宣言されていれば、それにも)、
あなたが指定した条件を満たすのに必要な全てのGemのリストを見つけ出します。
あなたのGemfile内の全てのgemも、それぞれが自身の依存関係を持つため(そして、更にそれらの幾つがまた依存関係を持ち)、
上記のGemfileのbundle install
実行は、かなりの数のGemをインストールします。
$ bundle install
Fetching gem metadata from https://rubygems.org/.........
Fetching additional metadata from https://rubygems.org/..
Resolving dependencies...
Using rake 10.3.1
Using json 1.8.1
Installing minitest 5.3.3
Installing i18n 0.6.9
Installing thread_safe 0.3.3
Installing builder 3.2.2
Installing rack 1.5.2
Installing erubis 2.7.0
Installing mime-types 1.25.1
Using bundler 1.6.2
Installing polyglot 0.3.4
Installing arel 5.0.1.20140414130214
Installing hike 1.2.3
Installing mini_portile 0.5.3
Installing multi_json 1.9.3
Installing thor 0.19.1
Installing tilt 1.4.1
Installing tzinfo 1.1.0
Installing rack-test 0.6.2
Installing rack-cache 1.2
Installing treetop 1.4.15
Installing sprockets 2.12.1
Installing activesupport 4.1.0.rc2
Installing mail 2.5.4
Installing actionview 4.1.0.rc2
Installing activemodel 4.1.0.rc2
Installing actionpack 4.1.0.rc2
Installing activerecord 4.1.0.rc2
Installing actionmailer 4.1.0.rc2
Installing sprockets-rails 2.0.1
Installing railties 4.1.0.rc2
Installing rails 4.1.0.rc2
Installing nokogiri 1.6.1
Your bundle is complete!
Use `bundle show [gemname]` to see where a bundled gem is installed.
必要なGemのうちの幾つかが既にインストールされていれば、Bundlerはそれを使用します。
システムへ必要なGemをインストールした後は、
Bundlerはインストールした全てのGemとバージョンをGemfile.lock
に書き込みます。
Bundlerを使用するためのアプリケーションの設定
Bundlerは、Gemfile内の全てのGem(と、全ての依存関係)を、Rubyが見つけることが出来るのかを確かめます。 もし、あなたのアプリケーションがRails3+であれば、デフォルトで既にBundlerを実行するのに必要なコードが含まれています。 もしRailsのバージョンが2.3であれば、 Setting up Bundler in Rails 2.3を参照してください。
その他のアプリケーションのフレームワーク(Sinatraのような)では、
必要とするGemを試す前にBundlerの設定が必要になります。
アプリケーションが読み込む最初のファイルの先頭に(Sinatraであれば、require 'sinatra'
を呼び出すファイル)、
下記のコードを埋め込んでください。
require 'rubygems'
require 'bundler/setup'
これは自動的にあなたのGemfileを発見し、
Gefmifle内の全てのGemがRubyで使用できるようにしてくれます。
(技術的な観点から言えば、"読み込みパス"にそれらのGemが設定された事になります)
require 'rubygems'
に対して、拡張機能が加えられたと考えても良いかもしれません。(翻訳に自信なし)
これであなたのコードがRubyで利用可能となり、必要なGemをrequireすることが出来ます。
例えば、require 'sinatra'
とする事が可能です。
もし多くの依存性を持つ場合、"Gemfile内の全てのGemをrequire"したいと考えるかもしれません。
これをするために、require 'bundler/setup'
のすぐ後に下記のコードを配置します。
Bundler.require(:default)
前述したGefileを例とすると、この行は実際には次のように評価されます。
require 'rails'
require 'rack-cache'
require 'nokogiri'
もしかしたら、あなたはrack-cacheのrequireの正しい指定方法が、require 'rack-cache'
では無く、
require 'rack/cache'
であることに気づいていいるかもしれません。
Bundlerにrequire 'rack/cache'
を使用することを伝えるために、Gemfileを更新してください。
source 'https://rubygems.org'
gem 'rails', '4.1.0.rc2'
gem 'rack-cache', require: 'rack/cache'
gem 'nokogiri', '~> 1.6.1'
このような小さなGemfileであれば、Bundler.require
の説明をスキップして、
手動でgemをrequireするようにアドバイスしたいところです。
(特に、Gemfile内の:require
指定子(ディレクティブ)が必要なケースもあるため)
規模の大きいGemfileでは、Bundler.require
を使用することで、
必要なGemの詰め込みの繰り返しをスキップすることが可能になります。
バージョン管理のコードを確認
アプリケーション開発後は、Gemfile
とGemfile.lock
のスナップショット(その瞬間のファイル)を一緒に、
アプリケーションにチェックインします。
これであなたのリポジトリはアプリケーションが動作していたことを最後に確認した時に使用していた、
全てのGemの実際のバージョンの記録を持つことになります。
ここで例に出したGemfileに記述されているGem(それぞれバージョン固定の制限が異なる)は3つだけですが、
実際にはかなりの数のGemにアプリケーションが依存しており、
暗黙的にrequireされる依存性のあるGemの全てについても考慮しておく必要があることを忘れないで下さい。
重要:Gemfile.lock
は、あなたのアプリケーションが全て動作していることを、あなたが最後に確認した、
あなた自身のコードとサードパーティ製のコードを1つのパッケージにしてくれます。
Gemfile
に書かれる依存関係のあるサードパーティ製のコードのバージョン指定は、
同一である事を保証するものではありません。
何故なら、通常それには依存するGemのバージョンが範囲指定で宣言されているからです。
再び同じマシン上でbundle install
を実行すると、
Bundlerは必要とされる全ての依存性が既に存在している事を確認し、インストール処理をスキップします。
.bundle
ディレクトリ、及びその中のファイルをチェックインしないで下さい。
これらのファイルは個別のマシン毎に指定され、
bundle install
の実行する際のインストールオプションを固定するのに使用されます。
もしbundle pack
が実行されると、
あなたのBundleに必要とされるGem(ただし、gitのGemでは無い)はvendor/cache
にダウロードされます。
もしソースの制御下で、そのフォルダに必要とする全てのGemが提供され、確認することが出来れば、
Bundlerはインターネット(またはRubygemsサーバー)への接続無しで実行できるようになります。
これは任意の手順であり、リポジトリ管理のソースコードの容量が増える傾向があり、
推奨されるものではありません。
他の開発者とアプリケーションを共有する
あなたの協同開発者(または別のマシン)が、あなたのコードをチェックアウトする際に、
あなたのマシン上で最後に開発を行った(Gemfile.lock
内の)サードパーティ製の正確なバージョンが取得されます。
**彼ら**がbundle install
を実行すると、
BundlerはGefile.lock
を見つけ、依存性解決の手順はスキップします。
代わりに、あなたの元のマシン上で使用されていたものと同じGemを全てインストールします。
言い換えれば、あなたはインストールすべき依存性のバージョンについて考える必要は無いということです。
先程、例として使用していたrack-cacheがrack >= 0.4
に依存すると宣言されていたとしても、
我々はそれがrack 1.5.2
で動作することが保証されていることを把握しています。
もしRack開発チームがrack 1.5.3
をリリースしていたとしても、
Bundlerは常に1.5.2
をインストールし、動作するGemの正確なバージョンを把握することが出来ます。
これは、常に全てのマシンが正確に同じバージョンのサードパーティ製のコードを実行するため、
アプリケーション開発者が抱えるメンテンナンスによる負荷を軽減することが出来ます。
依存性の更新
もちろん、ある時点でアプリケーションが依存する特定のGemの依存性のバージョンを更新したいと考えるようになるかもしれません。
例えば、あなたはRailsを4.1.0
finalに更新したくなるかもしれません。
重要なことですが、あなたが1つの依存関係を更新しているからといって、
あなたが全ての依存関係を再解決し、全ての最新バージョンを使用したいという意味では無いはずです。
ここでの例は3つの依存性しかありませんが、それでも全てを更新しようとすると複雑な状態になる可能性があります。
実例で説明すると、rails 4.1.0.rc2
のGemは、
rack ~> 1.5.2
(>= 1.5.2 且つ < 1.6.0 という意味)に依存した、
actionpack 4.1.0.rc2
のGemに依存している、といった具合です。
rack-cache
のGemはrack >= 0.4
に依存しています。
仮にrails 4.1.0
finalのGemもrack ~> 1.5.2
に依存しており、
rails 4.1.0
のリリース以降、Rackチームがrack 1.5.3
をリリースしたとしましょう。
もし単純にRailsを更新するためにGemを全て更新しようとすると、
rails 4.1.0
とrack-cache
の両方の依存関係を満たすrack 1.5.3
を取得します。
ただし、我々はrack 1.5.3
と互換性がないかもしれないrack-cache
の更新を明確に求めることをしていません。(どんな理由であれ)
そして、rack 1.5.2
からrack 1.5.3
への更新はおそらく何も問題は起こらないでしょうが、
同様の事をして大事になることもあるかもしれません。
([1]参照)
この問題を避けるために、あなたがGemを更新する際に、Bundlerは他のGemがそのGemに未だ依存しているのであれば、
そのGemの依存性を更新しません。
この例であれば、rack-cache
はまだrack
に依存しているため、
Bundlerはrack
のGemを更新しません。
これはRailsの更新の際に、不注意でrack-cache
を壊してしまわないことを保証します。
rails 4.1.0
のactionpack 4.1.0
依存関係は、
依然としてrack 1.5.2
との互換性を持つため、
Bundlerはそれを単独で残し、rack 1.5.3
との非互換性と直面しても、
rack-cache
は動作し続けます。
元々はrails 4.1.0.rc2
への依存を宣言していたため、
もしrails 4.1.0
へ更新したいのであれば、
Gemfile
をgem 'rails', '4.1.0'
に更新して、それを実行します。
$ bundle install
前述したとおり、bundle install
コマンドは常に保守的な更新を行い、
あなたがGemfile
内で明確に変更していないGem(またはその依存性)の更新を拒絶します。
これは、もしあなたがGemfile
内でrack-cache
を修正しなければ、
Bundlerは、それと、その依存性(rack)を単一のもの、修正できない集まり、として取り扱う事を意味します。
もしrails 4.1.0
がrack-cache
と互換性が無い場合、
Bundlerは依存性のスナップショット(Gemfile.lock
)と更新されたGemfile
との間に、
衝突があることを報告します。
もしあなたがGemfile
を更新し、システムが既に必要とされる依存性を全て持つ場合、
アプリケーションの起動時に、Bundlerはあなたに意識させること無くGemfile.lock
を更新します。
例えば、もしGemfile
にmysql
を追加し、既にそれがシステム内にインストールされていた場合、
bundle install
の実行無しにアプリケーションを起動する事が可能で、
BundlerはGemfile.lock
スナップショットに、前回正常起動時("last known good")の構成を引き継ぎます。
最小の依存性(データベースドライバ、wirble
、ruby-debug
)でのGemの追加または更新時は、
手動で行うことが可能です。
もし、大規模な依存性(例えばRails)または多くのGemへの依存(rack)を伴うGemの更新をする場合、それはおそらく失敗するでしょう。
もし意識させないで行われるGemfile.lock
の更新が失敗すると、アプリケーションの起動は失敗し、
Bundlerはbundle install
の実行を指示するエラーを出力します。
Gemfileを変更せずに、Gemを更新
時に、Gemfileの修正無しに依存性の更新行いたいというケースがあるでしょう。
例えば、あなたはrack-cache
を最新バージョンに更新したいと考えるかもしれません。
何故なら、Gemfile内にrack-cache
のバージョン指定を宣言していないため、
rack-cache
の最新バージョンを定期的に取得したいと考えているかもしれません。
これを行うには、bundle update
コマンドを使用します。
$ bundle update rack-cache
このコマンドは、rack-cache
を更新し、Gemfile
による、その最新バージョンへの依存関係を許可します。
(このケースでは、利用可能な最新のバージョン)
これは、その他の依存関係にあるものの変更を行いません。
ただし、もし必要となれば他のGemへの依存関係の更新が行われます。
例えば、もしrack-cache
の最新バージョンが、rack >= 1.5.2
への依存性を指定していた場合、
Bundlerはあなたがrackの更新を指示していなくても、rackを1.5.2
へ更新します。
もしBundlerがその他のGemの依存関係の更新を必要とする場合は、
それは更新が完了した後にあなたに知らされます。
もし可能な限り最新のバージョンでGemfile内の各Gemを更新したいのであれば、 次のように実行します。
$ bundle update
これはGemfile.lock
を無視して、ゼロから依存性を解決します。
もしこれを行うと、git reset --hard
と背面のテストスイートが維持されます。
ゼロから全ての依存性を解決することは、驚く結果になる可能性があり、
特に依存性のある多数のサードパーティ製のパッケージを、最後の全ての更新から最新のバージョンに更新する場合は、
そういった事が起こりやすいでしょう。
概要
シンプルなBundlerのワークフロー
-
あなたがRailsアプリケーションを作成する際には、最初から
Gemfile
は存在しているはずです。 その他のアプリケーション(Sinatraのような)では、下記を実行してください。$ bundle init
bundle init
コマンドは、編集されるための単純なGemfile
を作成します。 -
次にあなたのアプリケーションに依存するGemを追加します。 もしGemが特定のバージョンであることに注意する必要がある場合は、 適切なバージョン制限を含めることでそれを確定して下さい。
source 'https://rubygems.org' gem 'sinatra', '~> 1.3.6' gem 'rack-cache' gem 'rack-bug'
-
もしシステムにまだGemがインストールされていなければ、下記を実行してください。
$ bundle install
-
Gemのバージョンを更新するには、まず
Gemfile
を修正します。source 'https://rubygems.org' gem 'sinatra', '~> 1.4.5' gem 'rack-cache' gem 'rack-bug'
そして、下記を実行します。
$ bundle install
-
もし
bundle install
がGemfile
とGemfile.lock
の間に衝突があると報告してきたら、 下記を実行してください。$ bundle update sinatra
-
これは単にSinatraのGemを更新するだけでなく、それに依存する全てのもの更新します。
-
Gemfile
内の全てのGemを可能な限り最新のものに更新するには、下記のように実行します。$ bundle update
-
Gemfile.lock
に変更があった場合は、それを必ずバージョン管理にチェックインしてください。 こうすることでアプリケーション実行が成功した際に使用された、 サードパーティ製のコード全ての実際のバージョンの履歴を保持することが出来ます。 -
コードをステージング、またはプロダクション環境のサーバーにデプロイする際には、 まずテストを実行(またはローカルの開発サーバーを起動)し、
Gemfile.lock
がバージョン管理へチェックインされている事を確認してください。 リモートサーバー上で、次のように実行します。$ bundle install --deployment
注釈
[1]
例えば、もしrails 4.1.0
がrack 2.0
に依存している場合、
依存性が>= 0.4
として宣言されているrack-cache
であれば、その必要性をまだ満たしています。
もちろん、あなたはバージョンの制限が無いrack-cache
に依存する事を馬鹿馬鹿しいと感じるかもしれませんが、
こういったシチュエーションは実際に存在し、プロジェクトは何のバージョンに依存するかを決定する際に、
どうにかしてそれらを見つけてくることがよくあります。(翻訳に自信なし)
あまりに依存性の制約を強くし過ぎる(rack =1.5.1
)と、
他の互換性のあるプロジェクトで、そのプロジェクトを使用することが困難になります。
あまりに依存性の制約を弱くしすぎる(rack >= 1.0
)と、
Rackの新しいリリースがあった際にコードが不具合を起こすかもしれません。
rack ~> 1.5.2
のような依存性の使用と、
SemVerによるバージョニングコードに沿った方法は、
これらの問題をほとんど解決しますが、それは普遍的なコンプライアンスに従っている事を想定としています。
Rubygemsには100,000を超えるパッケージがああるため、
実際にはこの想定通りにはいかないことがあるでしょう。
© 2010 - 2017 STUDIO KINGDOM