rubygemのインストール先と、requireでどのように呼び出して使っているかを調べた。

概要

rubygemを作って公開しよう!と意気込んでいろいろ情報を集め、さあ作るぞ!ってなったときに、ふと、

「いままでrailsプロジェクトでさんざん使ってきたけど…gemってどこにインストールされて、どういう仕組みで読み込んで使ってるんだ?」と疑問が湧いてきた。

なので調べた。

結論

bundle installでインストールされたgemは、$ gem environmentの出力結果のINSTALLATION DIRECTORY に配置され、requireで組み込み変数$LOAD_PATH内のパスを起点として検索され、呼び出され、使用できるようになっている。

gemのインストール先

bundle installでインストールされたgemは、$ gem environmentの出力結果のINSTALLATION DIRECTORY に配置される。

$ gem environment 
RubyGems Environment:
  - RUBYGEMS VERSION: 3.2.3
  - RUBY VERSION: 3.0.0 (2020-12-25 patchlevel 0) [x86_64-darwin19]
  - INSTALLATION DIRECTORY: /Users/horimotonaomichi/.rbenv/versions/3.0.0/lib/ruby/gems/3.0.0
  - USER INSTALLATION DIRECTORY: /Users/horimotonaomichi/.gem/ruby/3.0.0
  - RUBY EXECUTABLE: /Users/horimotonaomichi/.rbenv/versions/3.0.0/bin/ruby
  - GIT EXECUTABLE: /usr/local/bin/git
  - EXECUTABLE DIRECTORY: /Users/horimotonaomichi/.rbenv/versions/3.0.0/bin
  - SPEC CACHE DIRECTORY: /Users/horimotonaomichi/.gem/specs
  - SYSTEM CONFIGURATION DIRECTORY: /Users/horimotonaomichi/.rbenv/versions/3.0.0/etc
  - RUBYGEMS PLATFORMS:
     - ruby
     - x86_64-darwin-19
  - GEM PATHS:
     - /Users/horimotonaomichi/.rbenv/versions/3.0.0/lib/ruby/gems/3.0.0
     - /Users/horimotonaomichi/.gem/ruby/3.0.0
  - GEM CONFIGURATION:
     - :update_sources => true
     - :verbose => true
     - :backtrace => false
     - :bulk_threshold => 1000
  - REMOTE SOURCES:
     - https://rubygems.org/
  - SHELL PATH:
     - /Users/horimotonaomichi/.rbenv/versions/3.0.0/bin
     - /usr/local/Cellar/rbenv/1.2.0/libexec
     - /Users/horimotonaomichi/.rbenv/shims
     - /Users/horimotonaomichi/.rbenv/bin
     - /Users/horimotonaomichi/.nodebrew/current/bin
     - /usr/local/bin
     - /usr/bin
     - /bin
     - /usr/sbin
     - /sbin

読み込みの仕組み

rubyrequireの読み込み対象は、rubyの組み込み変数$LOAD_PATH内のパスを起点とし、相対パスでファイルを検索する。

検索の仕組みは単純で、

  1. $LOAD_PATH($:)を順に辿る
  2. 目的のファイルが見つかったら終了
  3. 最後まで来たらLoadError例外

$ ruby -e 'puts $LOAD_PATH'とすると、$LOAD_PATH内に格納されているパスを見ることができる。

$ ruby -e 'puts $LOAD_PATH'
/usr/local/Cellar/rbenv/1.2.0/rbenv.d/exec/gem-rehash
/Users/horimotonaomichi/.rbenv/versions/3.0.0/lib/ruby/site_ruby/3.0.0
/Users/horimotonaomichi/.rbenv/versions/3.0.0/lib/ruby/site_ruby/3.0.0/x86_64-darwin19
/Users/horimotonaomichi/.rbenv/versions/3.0.0/lib/ruby/site_ruby
/Users/horimotonaomichi/.rbenv/versions/3.0.0/lib/ruby/vendor_ruby/3.0.0
/Users/horimotonaomichi/.rbenv/versions/3.0.0/lib/ruby/vendor_ruby/3.0.0/x86_64-darwin19
/Users/horimotonaomichi/.rbenv/versions/3.0.0/lib/ruby/vendor_ruby
/Users/horimotonaomichi/.rbenv/versions/3.0.0/lib/ruby/3.0.0
/Users/horimotonaomichi/.rbenv/versions/3.0.0/lib/ruby/3.0.0/x86_64-darwin19

疑問点

bundle install —path vendor/bundleでインストールした場合はどうなる?

プロジェクト内のvendor/bundleディレクトリにインストールされる。これをそのままrequireはできないので、プロジェクト内にインストールしたgemを読み込んで使用するためのBundler.requireメソッドがある。

ただし、Bundler 2.1 以降、 --pathオプションは deprecated(非推奨) となっており、基本的にはgemはグローバルにインストールして使うのが主流っぽい。

参考:

Railsの場合は?

Railsプロジェクトにおいても、bundle installのインストール先は$ gem environmentの出力結果のINSTALLATION DIRECTORY

railsではgemをrequireする必要はない。

理由はconfig/application.rbにGemfile内のgemを一括で読み込む設定がなされているため。

参考:

感想

gemのインストール先を調べていくうちに、requireの仕様まで学ぶことができてよかった。

また、gemはグローバルにおいて使うのが主流ということもわかった。なんとなーく「グローバル汚染するのはよくないのかなあ?」と思っていたのがスッキリした。