[Ruby] Bundled gemsはGemfileに指定して使おう
まとめ
-
Rubyインストール時に同梱されるgemは、Standard gemsと呼ばれるが、これらはDefault gemsとBundled 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
に失敗した
- トラブル例: 古いRubyのバージョンのプロジェクト中で使っているライブラリが、Rubyの新バージョンでBundled gemになっていて、新しいRubyで
-
Bundled gemsのリストは、gems/bundled_gemやhttps://stdgems.org/で確認できる
Rubyインストール時に同梱されるgemには2種類ある
Rubyインストール時に、gemの形式で一緒にインストールされるライブラリが幾つかあります(例:json, minmitest)。これらは、Standard gemsと呼ばれます。
Standard gemsは、さらにDefault gemsとBundled 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コアの外でメンテナンスされる)
bundle install
する
Bundled gemは、Gemfileに指定&Bundlerを使っているプロジェクトでは、bundle exec
コマンドで、システムにgem install
したgemではなく、Gemfileに指定したgemを利用します。
Bundled gemsは3rd party gemと同じなので、Gemfileに指定してbundle install
しない限り、require
することができません。
最近のRubyのリリースノートの
以下のライブラリが新たに bundled gems になりました。Bundler から利用する場合は Gemfile に明示的に指定してください。
これらは bundled gems になりました。Bundler とともに利用するときは Gemfile に書くのを忘れないようにしてください。
の一文は、この事情を指しています。
実験
例えば、bundle init
したディレクトリ内で、Default gemであるjsonとBundled gemであるminitestをrequire
する以下のようなファイルを作成し(ここでは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
でも問題なく動作します。
# 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 exec
でrequire
に失敗するライブラリ」に見えてしまうかもしれません。
前掲のとおり、Default gemsは、リリースノートの他にgems/bundled_gemやhttps://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があるので、将来公式で用意されるかもしれないです。
参考(注釈に無いもの)
- [JA] How to develop the Standard Libraries of Ruby? / Hiroshi SHIBATA @hsbt
- RubyKaigi 2017 に登壇します & GMO ペパボがスポンサードします
- Gemifying Ruby standard library
-
https://tech.pepabo.com/2017/09/11/rubykaigi-2017/#bundled-gems ↩︎
-
https://www.slideshare.net/hsbt/gemification-for-ruby-2530/28 ↩︎
-
https://www.ruby-lang.org/ja/news/2021/12/25/ruby-3-1-0-released/ ↩︎
-
https://www.slideshare.net/hsbt/gemification-for-ruby-2530/12 ↩︎
-
[JA] Gemification for Ruby 2.5/3.0 / SHIBATA Hiroshi @hsbt ↩︎
Discussion