きみはねこみたいなにゃんにゃんなまほう

ねこもスクリプトをかくなり

Bundler の bundler/setup と bundle exec

(=˘ ꒳ ˘=) Ruby のコードちんぷんかんぷんで読みづらい... import やら require やら load やら色々読み込みの構文があるのに加えて、どのライブラリから来た定義なのかが追いづらかったり...

...という愚痴は置いておいて、Ruby のモジュールシステムを別の方面からややこしくしている Bundler の振る舞いについて整理したいと思います。ややこしいと書きましたが、プロジェクト下に依存ライブラリを置けるという、Node.js から来た身からすると勝手知ったるベンダリング手法が取れるありがたいツールです。

Bundler がインストールしたパッケージを使うためには bundle exec したり require bundler/setup したりと、いくつかお作法が必要そうなのですが、それぞれどう作用するかを実際に動かしながら整理していきます。

公式の記述は How to use Bundler with Ruby にあります。しかし情報がパラパラしていて追いづらかったので実際に試してみることにしたのでした。

試してみる

├── Gemfile
├── bin
│   ├── with-bundler-setup.rb
│   └── without-bundler-setup.rb
├── lib
│   └── using-bundled-packages.rb
└── vendor

というプロジェクトを用意します。 https://github.com/asa-taka/try-module-on-bundler に実際のファイルを置いておきました。

フロントのスクリプトをふた通り用意します。

# bin/with-bundler-setup.rb
require 'rubygems'
require 'bundler/setup'
require './lib/using-bundled-packages'
# bin/without-bundler-setup.rb
require './lib/using-bundled-packages'

require の振る舞いを見たかったので一段 lib/using-bundled-packages.rb というスクリプトを挟んでいます。

# lib/using-bundled-packages.rb
require 'awesome_print'

として awesome_print を呼んでいます。vendor 下にインストールされた awesome_print には print 'awesome_print by bundler loaded' と仕込んで、Bundler によりインストールされたパッケージが実行された場合にテキストがプリントされるようにしました。

試した結果

bundle exec ruby ./bin/with-bundler-setup のように各組み合わせを試したところ以下のような結果になりました。

実行コマンド bundler/setup なし bundler/setup あり
ruby .... global のパッケージ Bundler によるパッケージ
bundle exec ruby ... Bundler によるパッケージ Bundler によるパッケージ

つまり bundle exec を使う、もしくはエントリポイントで require bundler/setup をすると孫 require でも Bundler によるパッケージが使われることになりますね。

毎回 bundle exec するのも面倒なので require bundler/setup の方が楽そうですね。

どういう処理でこうなっているのかはまた掘り下げてみたいところです。