おもしろwebサービス開発日記

Ruby や Rails を中心に、web技術について書いています

bundlerのREADMEを読んでのメモ

bundlerのREADMEを読んでの自分用メモ&意訳。

bundle init

Gemfileのひな形の作成用のコマンド。Gemfileの書き方の情報はBundler::Dslを参照するといい。

Gemfileの書き方

source

gemファイルのソースを指定。最低一個は指定する必要がある。

source :gemcutter

git

sourceに追加したいgitリポジトリを指定する。

git "git://github.com/indirect/rails3-generators.git"

path

ローカルのgemを追加したい時に指定

path "/path/to/rails", :glob => "{*/,}*.gemspec"

gem

見たまんま。

gem "rack", "1.0.0"

group

プラグインを使いたいenvironmentsを指定。gemのオプションとしても指定できるし、ブロックを持つメソッドとしても使える。

gem "nokogiri", :group => :test

# or

group :test do
 gem "webrat"
end

groupを指定しないとき、全てのgemは:default groupになる

  1. bundle installでインストールしたとき、--without group1 group2 のようにすることで指定したgroupをつかわないようにすることができる。特定環境でコンパイルできないgemがあるときに使える。
  2. Bundler.setupを使ってload pathをセットするときに、Bundlerはデフォルトで全てのgroupにload pathを追加する。Bundler.setup(:group, :name)を使うことでgroupへのload pathの追加を制限することが出来る。そのようにしたときには、defaultグループにload pathを追加したければ :default を明示的に指定する必要がある。
  3. Bundler.requireを使用してGemfileに書いてあるgemを自動でrequireするとき、Bundlerはデフォルトで:default groupにrequireする。Bundler.require(:default, :test)のようにすることで自動でrequireするgroupを特定できる。

installing gems

bundle installでbundlerのgemリポジトリにgemがインストールされる。gemが既にrubygemsリポジトリにインストールされていれば、再びインストールはせずにそこを参照するようにする。Gemfileをアップデートしたら、再びbundle installする。

bundle install vendorとするとvendorディレクトリの配下にgemをインストールできる。

Locking dependencies

デフォルトで、bundlerはGemfileの依存関係を満足させることを保証する。もし新しいバージョンのgemがインストールされてそのgemが依存関係を満たすものであれば、新しいgemを利用する。

もしアプリを配布するようなとき、GemfileとGemfile.lockファイルをリポジトリに入れるべき。それらはアプリのライブラリのバージョンを固定する。チェックアウトした後にbundler installしたときに、ライブラリがちゃんと動くことを保証する。

.bundleディレクトリをリポジトリに入れちゃダメ。このファイルはbundlerの内部用のファイルでPC毎に変わる。もしgitを使っているなら、PC固有のbundlerファイルを.gitignoreに.bundleを入れることで排除することができる。

Running the application

bundlerは他のものがrequireされる前にrequireされてセットアップされる必要がある。全てのload pathを設定してgemの管理をするから。そのために、コードの最初に下記のようなコードを含む必要がある。

begin
  # Try to require the preresolved locked set of gems.
  require File.expand_path('../.bundle/environment', __FILE__)
rescue LoadError
  # Fall back on doing an unlocked resolve at runtime.
  require "rubygems"
  require "bundler"
  Bundler.setup
end

# Your application's requires come here, e.g.
# require 'date' # a ruby standard library
# require 'rack' # a bundled gem

# Alternatively, you can require all the bundled libs at once
# Bundler.require

bundle execコマンドを使うことで、任意のrubyコードをbundleのコンテキストで動かすことが出来る。

bundle exec ruby my_ruby_script.rb

全てのgemを利用可能な状態にしてシェルを使いたいときは下記のようにする。

bundle exec bash(or zshとか)

いまいち使いどころがわからない。

Packing the bundle's gems

デプロイしたアプリを共有するときに、必要な全てのgemを一緒に共有したいと思うかもしれない。bundle packageは全てのGemfileに書かれた依存性のある.gemファイルをvendor/cacheにコピーする。。その後に、bundle installを使うと、ローカルの.gemファイルをインストールする。外部のリポジトリにはアクセスしない。

gem resolution

bundlerが行う最も重要なことの一つは、Gemfileに書かれたリストの全てのgemの依存性の解決を一度にやってしまうこと。これはRubygemが行うone-at-a-timeの依存性の解決とは異なる。Rubygemだと下記のような問題が起こる

# インストール済みのgem
#   activesupport 3.0.pre
#   activesupport 2.3.4
#   activemerchant 1.4.2
#   rails 2.3.4
#
# activemerchant 1.4.2 には activesupport >= 2.3.2 が必要

gem "activemerchant", "1.4.2"
# activemerchant をアクティベートするには activesupportの2.3.2以上が必要なので
# activesupport 3.0.preがアクティベートされる


gem "rails", "2.3.4"
# activesupport 2.3.4が必要だが、既にactivesupport 3.0.preがアクティベートされているので
# activesupport 2.3.4はアクティベートできない。

activemerchantが広い依存性を持っていて、それによりactivesuppportのバージョンがより狭い依存性を満たせなくなってしまっている。

Bundlerはこの問題を全ての依存性を一度に評価することで解決している。上記の例では全てのgemがactivesupoprt 2.3.4を必要としていることを検知する。