結論
bundle install
実行時は、
- まずコマンド実行時の階層のGemfile, gems.rbの存在を確認
- 存在しなかったら上の階層を探しに行く、を探せるまで繰り返す
開発環境
> bundle -v Bundler version 2.3.17
モチベーション
bundle install
実行時に、直下にGemfileが無いのにも係わらず実行されたことに驚いた。
試した感じ親階層のGemfileを参照しているように見えるが、実際の動きを確認する。
あとiOSアプリ開発でRubyはちょくちょく絡んでくるのでRubyのソースコードを読めるようになりたい。
Bundlerの公式ドキュメント
This defaults to a Gemfile(5) in the current working directory. In general, Bundler will assume that the location of the Gemfile(5) is also the project's root and will try to find Gemfile.lock and vendor/cache relative to this location. https://bundler.io/v2.3/man/bundle-install.1.html
- デフォルトで現在の作業ディレクトリのGemfileを参照
- 一般的にBundlerはGemfileの場所がプロジェクトのルートにあると想定し、その場所にGemfile.lockとvendor/cacheを見つけようとする
コード
エントリーポイントから辿ると、rubygems/bundler/lib/bundler/shared_helpers.rb#search_up(*names)
に辿り着いた。
# https://github.com/rubygems/rubygems/blob/eba5fc5fccc822f7cb859c7c51f657c3ffdec507/bundler/lib/bundler/shared_helpers.rb#L260 current = File.expand_path("..", current)
ここで、今見ている階層にGemfile, gems.rbが無ければ上の階層を見るようにしている。
杞憂?
コード見た感じ+手元で試した感じ、bundle install
時にgit管理関係なく上の階層を探し続けてしまうのでパスを指定したほうが精神衛生的に良さそう。
> tree -f . ├── ./Gemfile ├── ./Gemfile.lock └── ./sub_d # Git管理しているルートのディレクトリ └── ./sub_d/hoge.txt
例えば上記のディレクトリ構成の時に、./sub_d
ディレクトリがGit管理しているルートのディレクトリの場合、意図せずに./sub_d
でbundle install
すると一個上の無関係のGemfileが参照されてしまう。本来ならインストールの処理は行わせたくない。…こんなディレクトリ構成ではあまり組まないか。杞憂っぽい。とはいえ一個上の階層見るのはやや予想に反して非明示的なので、自分はパス指定する形を取りたい。
> tree . ├── Gemfile ├── Gemfile.lock └── root_d └── hoge.txt > cd root_d > bundle config set --local path './../Gemfile' > bundle install Fetching gem metadata from https://rubygems.org/.......
気になったコード
# https://github.com/rubygems/rubygems/blob/eba5fc5fccc822f7cb859c7c51f657c3ffdec507/bundler/lib/bundler/shared_helpers.rb#L221_L223 def gemfile_names ["gems.rb", "Gemfile"] end
Rubyはガッツリ書いたことが無いので作法を知らないが、配列の宣言を定数/変数で行わずにメソッドを用意していることが気になった。引数無いし、固定の値を返すので定数で良いのでは?このメソッドが宣言されているモジュールという概念には定数を宣言できるみたい*1なので、定数を宣言しても良さそう。