bundlerは、Gemfile
に記述したRuby gemsを維持するパッケージマネージャです。複数のプロジェクトを管理する場合には、bundlerの挙動をよく理解しておくと便利です。
bundlerが不要なケース
bundlerはプロジェクトごとにgemセットを分離する目的のツールです。
たとえばコンテナのように各プロジェクトの環境が混ざることがないのであれば、bundlerを使わない方が維持しやすいケースがあります。
この場合には単にgem install
でグローバルにインストールします。gemが提供するCLIには後述のbundle exec
をつけずに実行します。
gemはgit経由のインストールをサポートしていないのですが、
specific_installプラグインを追加すると対応します。
コンテナ用途によく使われるdebian:slim
の場合、次のような流れになります。
# gemコマンドとrubyのインストール
apt install ruby-rubygems
# specific_installのインストール
gem install specific_install
# git経由のgemインストール。-dオプションはmonorepoの場合のサブディレクトリ指定
gem specific_install https://github.com/chumaltd/luca -d lucabook
bundlerを導入すると参照関係が複雑になるため、bundlerを排除するセットアップの方が長期メンテナンス時の挙動は明瞭です。
プロジェクト別のgemをインストールする
bundlerを利用すると、任意のpathにgemをインストールできます。インストール先のディレクトリはbundle install
を実行する前にbundle config
で設定しておきます。
なお、インストールオプションのbundle install --path
は既にobsoleteです。
$ bundle config --local path vendor/
紛らわしいのですが、--local
オプションはインストール先を指定するものではなく、configじたいの保存先(.bundle/
)をカレントディレクトリに指定するものです。
--local
を付けないデフォルト挙動ではユーザーのホームディレクトリとなり、プロジェクトごとの切り分けができません。
他の bundle configオプションについては、
公式リファレンスを参照してください。
binstubsでbundle execを省略する
rubyのgemの中にはコマンドラインツールを提供するものがあり、bundle install
でインストールすると、bundle exec
つきで実行できます。
さらに、bundlerのbundle binstubs
コマンドを実行すると、bundle exec
をつけずに実行可能なラッパースクリプトを生成でき、期待どおりrails new
の形式で利用できます。
コマンドの書式は以下の通りです。
$ bundle binstubs some_gem --path=some_path
引数はコマンド名ではなくgemの名称です。よって、rails
コマンドをセットアップしたい場合にはrailties
を指定します。複数のgemをターゲットにする場合はスペース区切りで羅列します。
--path
オプションにはスクリプトをインストールするpathを指定します。一般的なコマンドのインストールと同様、PATHの通ったディレクトリを指定することで、コマンド名のみで実行可能になります。プロジェクト内にインストールすることもグローバルディレクトリにインストールすることも可能です。
コマンド例のとおりbundle binstubs
はインストール済のgemを参照するため、bundle install
でひと通りgemをインストールしたあとに実行します。
なお、binstubsが生成するファイルは、gemが供給するrubyプログラムではなく、簡潔なシェルスクリプトです。gemをアップグレードした場合にも、実行ファイルの変更は基本的に必要ありません。
自作ツールをbundle
自分で作ったスクリプトをgemにしておくと、RubyGemsで配布されているgemと同様にbundlerで管理できます。
自作gemの詳細については、
Ruby自作ライブラリの管理で解説しています。bundlerは、gitやローカルのPathにも対応しているため、必ずしもRubyGemsで公開する必要はありません。
Gemfileでpath
参照しているgemについては、インストール・アップデートも必要なく、つねに自分で書いた最新版を参照します。
また、bundle installしておけば自作gemにもbinstubsを作成できるため、CLIツールを書くと一般的なコマンドと同様に利用できます。
ネイティブモジュールのコンパイル
依存しているgemがネイティブモジュールを含む場合、bundle install
プロセスでCなどのコンパイルを求められます。ビルドエラーに対処するには、Cのビルドに関する基礎知識が必要になります。
まず、Cのツールチェインをインストールしておく必要があります。rubyのネイティブ拡張ビルドがどのツールに依存しているかは自明ではありません。
Debian12の場合、gcc, make, ruby3.1-dev, libc-devが最低限必要でした。
また、各gemが依存しているCライブラリとヘッダー(Debianの場合は-devパッケージ)も必要でしょう。
rubyツールチェインはネイティブモジュールのC依存をまったく解決しないため、ビルドエラーが頻発します。
net-imapの
date dependency requires native compilationの議論のように、default gemもバージョンアップがあるとビルドする挙動になります。bundlerはGemfileにversion指定がない場合、アグレッシブに最新バージョンを選択するようです。
また、Cのビルドツールは200MB超のディスク消費を必要とするため、コンテナ用途では期待に反してイメージが肥大化します。
ビルドツールは実行時には不要であるため、必要に応じてビルドステージと実行環境を分割するといった工夫をすることになるでしょう。
Chuma Takahiro