それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

bundlerを使い始めた時に詰まったので調べた。

bundle 最初に知ること

bundler で出来ることを最初に知ることが必要

bunder はプロジェクトで使ってるgem を一覧するためのもの。

bundler は 必要なgem をインストールしてくれる

bundler は、自作ライブラリのgem化が出来る

bundler は、プロジェクトに必要なGemを「プロジェクト毎」にインストール出来る

bundler は、共有gem とプロジェクトで足りないものをインストール出来る。

つまり、bundler を使うことで、「必要なGem」の一覧を管理することが出来る。

このことにより、デプロイ先に開発元と同じgem環境を再現することができる

bundler 始め方

ディレクトリにGemFileを作成する。

もしくは、コマンドラインで bundle init とする

基本的な流れやで

sudo apt install ruby-bundler
mkdir プロジェクト
cd プロジェクト
bundle init 
bundle config set --local path 'vendor/bundle'
echo gem "nokogiri" >> GemFile
bundle install 

なにか追加したいときは、マニュアルで編集するか

vim GemFile
bundle install

または、bundle add する

bundle add sqlite3

プロジェクトの中にインストールする場合(2023-08-10追記)

bundle コマンド導入後なら、次をコピペすれば、プロジェクトごとに分離したbundler 環境を作れる。

mkdir my-project
cd my-project

bundle init
bundle config set --local path 'vendor/bundle'
bundle config set --local disable_shared_gems true
bundle add sqlite3

プロジェクト内部でruby を実行するとき

bundle 経由で実行する

bundle exec ruby sample.rb

sample.rb ではrequire するだけでいい。

# in sample.rb 
require 'sqlite3'

つぎに GemFile の書きかた。その0。

はじめに、source を書く。

source "https://rubygems.org"

これにより、gemをどこから探すか指定することが出来る。

自作レポジトリも指定できる。

source "https://rubygems.org"
source "https://takuya.example.org"

作成方法はgem generate_indexなどでググれば出てくる。

 GemFile の書きかた1

GemFileには、必要なGemを書いていく。

gem "nokogiri"
gem "pry"
gem "sequel"

GemFile の書き方2

必要なgem ファイルは、グループ分けすることが出来る

gem "nokogiri"
group :development do 
     gem "pry"
group :test do 
 gem "shoulda"
end

グループ分けしておくと、便利なことがある。

  1. デプロイ先で無駄なインストールしなくて便利だ
  2. bundle.require でグループ毎にreuqire 出来て便利。

GemFile の書き方3

バージョンを指定することが出来る

gem "nokogiri", ">= 1.4.2"

バージョン指定の方法は ruby require や gem install で用いられるものと同じだと思えばイイ。

bundler が使うファイル。

  • GemFile  使う(依存する)gemの一覧
  • GemFile.lock (実際に使ってる)gemとそのバージョン一覧

おもに GemFile が使われる。

GemFile.lockがBundlerで実際にインストールされたバージョンの一覧。

lock ファイルの記述を優先してインストールすることになる

lockファイルの扱い

gem file lock 記述を優先してインストールを再現される。が、、困った現象が起きた経験がある。

Bundlerが windows バイナリをOSXに入れようとしてて驚愕。OSXCygwinのバイナリ入れたら動かんだろう?でもインストールしてた。それがlockファイル。

Windowsバイナリでトラブルったのでgemfile.lock は細かく管理したい時に用途を限ることにした。バージョンやバイナリを詳細設定するときに限る。

Windows(開発)→Linux(デプロイ)のときは、全く役に立たないし、lockは消して構わない。gemfile.lock があるせいで、lockファイルはゴミ

bundler を使ったrequie 

bundle install のやり方が分かったら、次に bundler を使ったrequire を覚えておく

require 'bundler'
Bundler.setup
require 'nokogiri'

はい、これでOK

Gem を何処に入れるのか

bundler が良く分からない理由はコレだと思う。

  1. bundler にgem 環境を プロジェクト毎に作らせる
  2. bundler にシステム環境へgemをインストールさせる。

この2パターンがあってですね。システム環境やユーザー環境のGEM_HOMEかプロジェクト環境を選ぶことが出来るわけ。

個人で使う分には、プロジェクト環境よりシステム環境やユーザー環境利用が幾分に楽。

disable shared gems = 1

共有のgem をdisabledにして、プロジェクト内にgem 環境をゼロから作る。

bundle install vendor/bundle --disable-shared-gems

この場合、システム環境のgemは全て無視される

または、.bundle/config にかく

echo  BUNDLE_DISABLE_SHARED_GEMS: '1' >> .bundle/config

これで、bundleはプロジェクト環境に全てのgemをインストールする。

  BUNDLE_DISABLE_SHARED_GEMSの功罪

bundle が良く分からない現代魔法になってるのは、shared_gems にあるとおもう。

 BUNDLE_DISABLE_SHARED_GEMS: '1'

システム環境のgemを使いたい時は、 BUNDLE_DISABLE_SHARED_GEMS: '1'を消す

一年くらい使っててbundle でプロジェクト毎にパッケージをインストールするのは無駄と思うようになった。

pry とか mysql2 とかいくつもインストールしてんだわ。

システムの libxml 環境変わったのに古いbundleがlib指してて反って面倒だったり。システム全体のgem 使って欲しい場面のほうが多かった。 とくに開発環境だと時間の無駄が多いので必要ない気がする。

デプロイ先なら  BUNDLE_DISABLE_SHARED_GEMS: '1' をした方がいいかも。

つまり、BUNDLE_DISABLE_SHARED_GEMSがあると同じgemをいくつもインストールするので、ちょっとイラッとする。

bundleの手軽さが死ぬきがする。bundleのよさは git clone ; bundle install ; ですぐ使えることだと思うんだ。

bundle の設定

bundle/config の上書き関係

たとえば、BUNDLE_DISABLE_SHARED_GEMSの設定は次の箇所で指定される。

~/.bundle/config
PROJECT/.bundle/config
bundle install --disable-shared-gems

の順番で、ユーザ → プロジェクト → コマンド実行時になる。

 bundle install は何処に入るのか

  1. bunele install は なにも設定をしなければ system のgem が使われる
  2. bundle install はなにも設定ををしなければ system の gem にインストールされる
  3. bundle install は gem listall の自動化になる。

ただし、BUNDLE_PATHが環境変数にあったり、disable-shared-gemsが指定されていればこの限りではない。

なので、油断してるとシステム環境にインストールされちゃったり、プロジェクト環境にインストールされちゃうので注意が必要

私の場合、rbenv 環境にgem がインストールされないと思って悩んでいたら

ユーザー環境にデフォルト設定が会った。 ~/.bundle/config に disable-shared-gemsが設定されていた。はぁ。。。

bundle list で bundleされた一覧を見る

rbenv やrubygems が管理してるgemに任せるのが楽だった。

takuya@~$ bundle config
Settings are listed in order of priority. The top value will be used.
bundle install

個人環境なら vendor/bundle 使うとかえって面倒かもね。 使わなくなったら

gem uninstall hogehoge
gem cleanup 

で消しちゃってもいいしrbenv環境ごとポイッ

個人のrbenv環境で使うなら、何も設定せずにbundle install 叩いてたほうが圧倒的に楽だと思った

同じファイルをいくつもシステムに持つのダルいしコンパイルオプション考えるの面倒だしさ 自分のプロジェクトってだいたい同じようなgem使ってるじゃん?大きく違うバージョンや環境でもない限り vendor  使う必要ないと思った。

gem のソースを追いかけるために、locate や mdfind して同じファイルが大量に来るのも気持ち悪い・・・

強制的にsystem に入れる方法

bundle install --system 

ただ、既存のlock やconfigがあるとうまく動かない

vendor/bundle を使う方法

bundle install vendor/bundle --disable-shared-gems

これは、shared-gem(さっき言及した、システム全体gem)を拒否して、vendor/bundle にゼロからgem 空間を構築する 必要なgems の全てがvendor/bundleに入ります。

path / disable-shared-gems はワンセットになってるので消しちゃうとちょっと面倒なことに

手元の環境で、vendor/bundle 使うと、ここが不便でいや何だけど。

bundle の設定

現在のbundler の設定は bundle config で確認できる

$ bundle config
Settings are listed in order of priority. The top value will be used.

bundle の設定は、プロジェクトとHOME_PATHの2つをマージして使う

~/.bundle/config
PROJECT_HOME/.bundle/config

の2つのymlをマージすることになる。

たとえば、bundle install nokogiriにビルドオプションを与えたい時

bundle config --global  build.nokogiri -- \
 --with-xml2-dir=`brew --prefix libxml2`\
 --with-xslt-dir=`brew --prefix libxslt`

とする。

全てのbundle install nokogiri に設定したいときは ~/.bundle/config に書く。

> cat  ~/.bundle/config
---
BUNDLE_BUILD__NOKOGIRI: "--with-xml2-dir=/usr/local/opt/libxml2 --with-xslt-dir=/usr/local/opt/libxslt"

*1

.bundle/config の設定項目

設定項目には次のようなものがある。

  • BUNDLE_PATH
  • BUNDLE_FROZEN
  • BUNDLE_WITHOUT
  • BUNDLE_BIN
  • BUNDLE_GEMFILE
  • BUNDLE_SSL_CA_CERT
  • BUNDLE_SSL_CLIENT_CERT
  • BUNDLE_CACHE_PATH
  • BUNDLE_DISABLE_MULTISOURCE
  • BUNDLE_IGNORE_MESSAGES

設定は、同名の環境変数でも上書きされる。 環境変数のほうが楽かも?

環境変数を使う場合

BUNDLE_BIN="vendor/bundle/bin" bundle install 

また、config を指定する時だけ、次のような読み替えが許されるっぽい

BUNDLE_PATH => path
BUNDLE_BIN => bin

設定ファイルとコマンドオプションは同じ設定項目を意味する。

BUNDLE_BIN: "./bin"
bundle config --global bin "./bin"

デプロイ

bundle が真価を発揮するのはここ。

bundle install --deployment

このコマンドで、GemFile.lock で指定されている必要なパッケージを取ってくる  GemFile はユーザー指定 Gemfile.lock は bundle が調べて必要だと判別した全て。

ちなみに、そういうのはネットから取ってこれない場合のために

gem package 

すると vendor/cache に貯めておいてくれるので git vendor/cache でもしとけばいいけど、、OS超えてまでまず動かないと思うしやらないと思う。

bundle install --deployment --path=vendor/bundle

で環境の再現ということで。

vendor/bundle に入れた場合

bundle exec nokogiri
bundle exec 

手元の環境で、vendor/bundle 使うと、ここが不便でいや何だけど。

その他の話題

bundle コマンドを補完したい

brew install ruby-completion
brew install bundler-completion

などと、補完もいっぱいある

2023-08-10

更新。

参考資料

http://bundler.io/v0.9/bundle_install.html

https://gist.github.com/kozy4324/5719555

http://stackoverflow.com/questions/8104370/what-does-it-mean-bundle-disable-shared-gems-1

http://xxxcaqui.hatenablog.com/entry/2013/02/11/013421

http://ruby.studio-kingdom.com/bundler/gemfile

*1:HOME_PATH を --global というのはセンスが無いと思った --user にして欲しい --global は etcを期待してしまうハマった