🕌

[Ruby] Bundled gemsはGemfileに指定して使おう

2021/12/30に公開

まとめ

  • Rubyインストール時に同梱されるgemは、Standard gemsと呼ばれるが、これらはDefault gemsBundled gemsの2種類に分かれる

  • Bundled gemsは、bundlerを利用するプロジェクトでは、Gemfileに指定&bundle installする必要がある

    • トラブル例: 古いRubyのバージョンのプロジェクト中で使っているライブラリが、Rubyの新バージョンでBundled gemになっていて、新しいRubyでbundle exec ruby foo.rbするとin `require': cannot load such file -- minitest/autorun (LoadError)のようにrequireに失敗した
  • Bundled gemsのリストは、gems/bundled_gemhttps://stdgems.org/で確認できる

Rubyインストール時に同梱されるgemには2種類ある

Rubyインストール時に、gemの形式で一緒にインストールされるライブラリが幾つかあります(例:json, minmitest)。これらは、Standard gemsと呼ばれます。

Standard gemsは、さらにDefault gemsBundled gemsの2種類に分けられます[1]

Default gems

Rubyの標準添付ライブラリのうち、gemとして切り出したライブラリです。
大仕事になるRuby本体のバージョン変更をせずとも、セキュリティfixなどの変更をgemの更新の形でリリース・利用できるのが旨味となります。

  • 削除できない
  • bundle installしなくても、初めからrequireして使える(※Bundler利用のプロジェクトの話)
  • gem listすると、gem名の後に(default: X.X.X)のような文字列がつく
  • (Rubyコアがメンテナンスする)

Bundled gems

標準添付ライブラリではないが、Ruby開発チームがみんなに使って欲しいので、Rubyインストール時にgem installされるgemです。
つまり、gem insallを叩かなくてもすぐにrequireできる(※非Bundlerプロジェクト)というだけで、取り回し方は、通常の3rd party gemと変わりません[2]

  • 削除できる
  • bundle installする必要がある(※Bundler利用のプロジェクトの話)
  • gems/bundled_gem[3]https://stdgems.org/で、Bundled gemsのリストを確認できる
  • (Rubyコアの外でメンテナンスされる)

Bundled gemは、Gemfileに指定&bundle installする

Bundlerを使っているプロジェクトでは、bundle execコマンドで、システムにgem installしたgemではなく、Gemfileに指定したgemを利用します。
Bundled gemsは3rd party gemと同じなので、Gemfileに指定してbundle installしない限り、requireすることができません。

最近のRubyのリリースノート

以下のライブラリが新たに bundled gems になりました。Bundler から利用する場合は Gemfile に明示的に指定してください。

や、プロと読み解く Ruby ○.○ NEWS

これらは bundled gems になりました。Bundler とともに利用するときは Gemfile に書くのを忘れないようにしてください。

の一文は、この事情を指しています。

実験

例えば、bundle initしたディレクトリ内で、Default gemであるjsonとBundled gemであるminitestをrequireする以下のようなファイルを作成し(ここではmain.rbとします)、

main.rb
require "json" # Default gem
require "minitest" # Bundled gem

puts "Hello, standard gems!"

rubyコマンドとbundle exec rubyコマンドの両方で実行してみます。

$ ruby -v
ruby 3.1.0p0 (2021-12-25 revision fb4df44d16) [x86_64-linux]

$ ruby main.rb
Hello, standard gems!

$ bundle exec ruby main.rb
main.rb:2:in `require': cannot load such file -- minitest (LoadError)
        from main.rb:2:in `<main>'

ここではGemfileにminitestを指定してあげると、(当たり前ですが)bundle exec rubyでも問題なく動作します。

Gemfile
# frozen_string_literal: true

source "https://rubygems.org"

gem "minitest" # 本当はちゃんとバージョンも指定しましょう
$ bundle install
Fetching gem metadata from https://rubygems.org/.
Resolving dependencies...
Using bundler 2.3.3
Using minitest 5.15.0
Bundle complete! 1 Gemfile dependency, 2 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.

$ bundle exec ruby main.rb
Hello, standard gems!

Rubyのマイナーバージョンアップ時に、引っかかるかも

標準ライブラリ(含むDefault gems)からBundled gemsへの変更は、毎年クリスマスに行われるRubyの新マイナーバージョン(3.Xとか2.XのX)リリースの際に発生します。
例えばRuby3.1.0では、net-popなどが新たにBundled gemになっています[4]

こういったgemをBundlerを利用するプロジェクトで使っている場合、「Rubyに同梱されるはずなのに何故かbundle execrequireに失敗するライブラリ」に見えてしまうかもしれません。

前掲のとおり、Default gemsは、リリースノートの他にgems/bundled_gemhttps://stdgems.org/で一覧できるので、この中にrequireに失敗したライブラリが含まれていないかどうかをまず確認してみましょう。

(おまけ)gem化が進む標準添付ライブラリ

標準添付ライブラリとは、gem installなしでrequireして使うことのできる、Ruby本体と一緒に配布されるライブラリです[5][6](例:date)(対義語:組み込みライブラリ)。

現在Rubyでは、標準添付ライブラリのgem化(Gemifying, Gemification)が進められています。Default gem化は一通り完了しているようです[7](すごい)。

主なモチベーションとしては、Ruby本体との独立性を高めることで、Rubyのリリースサイクルを安定させたり、ライブラリ修正(特に脆弱性対応)やバックポートのサイクルが柔軟にできたり、(Rubyコアと違って)GitHub上にリポジトリができることで、contributionの発生機会が増えること等があります[8]。ユーザとして嬉しい取り組みですね。

このページで説明した内容についてのドキュメントは、Issueがあるので、将来公式で用意されるかもしれないです。

参考(注釈に無いもの)

脚注
  1. https://stdgems.org/ ↩︎

  2. https://tech.pepabo.com/2017/09/11/rubykaigi-2017/#bundled-gems ↩︎

  3. https://www.slideshare.net/hsbt/gemification-for-ruby-2530/28 ↩︎

  4. https://www.ruby-lang.org/ja/news/2021/12/25/ruby-3-1-0-released/ ↩︎

  5. 「Ruby用語集」の『標準添付ライブラリー』 ↩︎

  6. https://www.slideshare.net/hsbt/gemification-for-ruby-2530/12 ↩︎

  7. https://redmine.ruby-lang.org/issues/5481#note-111 ↩︎

  8. [JA] Gemification for Ruby 2.5/3.0 / SHIBATA Hiroshi @hsbt ↩︎

Discussion