rubygems-bundlerのしくみ

https://github.com/mpapis/rubygems-bundler

rubygems-bundlerを入れると、bundle exec がいらなくなるということを知りました。

どうやってbundle execを省略できるようにしてるのかわからなかったので、調べてみました。

結論としては、gem がインストールした実行ファイルの shebang を書き換えることで、フックしてます。

たとえば rbenv を使ってて、rakeをインストールすると、 /home/hoge/.rbenv/versions/2.1.1/bin/rake のようなパスに実行ファイルが作られます。

このファイルのshebangは、通常

#!/usr/bin/env ruby

なんですが、gem regenerate_binstubs を実行すると、これらのファイルのshebangだけを

#!/usr/bin/env ruby_executable_hooks

と書き換えてしまいます。 この ruby_executable_hooks というのが各Gemの中に lib/rubygems_executable_plugin.rb というのを探して、あればそれを実行します。

rubygems-bundlerrubygems_executable_plugin.rb は、カレントディレクトリからルートにむかって Gemfile を探し、あればそのファイルを使って Bundler.setup を呼び出します。

こうして bundle exec をつけずに rake を実行しても、 bundle exec をつけて呼び出したのと同様の効果を実現してます。

gem regenerate_binstubsコマンドを提供している executable-hooks は、Gemがインストールされるときにフックを走らせることで、以後は、実行ファイルを提供するGemがインストールされるごとに、自動で shebang を書き換えます。