Ruby RubyKaigi RubyGems Bundler

RubyKaigi 2017 に登壇します & GMO ペパボがスポンサードします

Ruby RubyKaigi RubyGems Bundler

執行役員 CPO (Chief Productivity Officer)の @hsbt です。

2017年9月18日(月)から20日(水)の期間、広島国際会議場で開催される RubyKaigi 2017 に私 @hsbt が以下の発表で登壇します。

本エントリでは、発表内容の事前知識として、 Ruby のスタンダードライブラリの現状についてご紹介します。

Ruby の標準添付ライブラリ

プログラミング言語 Ruby には、ネットワーク通信、CSV/XML などのフォーマットのファイルの操作、ffi や openssl などのミドルウェアのラッパーなど様々な種類のライブラリが付属しています。これらのライブラリはインストール直後から使えます。このインストール直後から使えるライブラリのことを標準添付ライブラリと呼んでいます。一方、Ruby インタプリタそのものに組み込まれているライブラリは組み込みライブラリと呼びます。

標準添付ライブラリは、現在 105 個存在しますが、これらのライブラリは書かれている言語により以下の二つに分類できます。

  • Ruby で書かれている標準添付ライブラリ
  • C で書かれている標準添付ライブラリ

また書かれている言語とは別に、添付形式によって以下の三つに分類できます。

  • Standard Libraries
  • Default gems
  • Bundled gems

上記の書かれている言語、添付形式を掛け合わせることで、Ruby の標準添付ライブラリは、さらに 6 種類のカテゴリに分類できます。具体的にどのライブラリがどのカテゴリに所属するか、という解説は省略しますが、105 個のライブラリのうち、7割弱が Ruby で書かれている Standard Libraries というのが Ruby 2.4 の現状です。

添付形式による振る舞いの違い

それでは今回は添付形式の違いによって Ruby をインストールし、使うときにどのような振る舞いの違いが発生するのかについて解説したいと思います。

Standard Libraries

Standard Libraries は Ruby をインストールしたディレクトリの lib 直下にインストールされるライブラリです。Standard Libraries は $LOAD_PATH に含まれるため、ユーザーはパッケージマネージャである RubyGems を用いなくても任意の ruby スクリプトから require することでライブラリを呼び出すことが可能です。

以下は私の環境で pp $LOAD_PATH を実行した結果です。

~ > ruby -rpp -e 'pp $LOAD_PATH'
["/Users/hsbt/.rbenv/rbenv.d/exec/gem-rehash",
 "/Users/hsbt/.rbenv/versions/2.5.0-dev/lib/ruby/gems/2.5.0/gems/did_you_mean-1.1.2/lib",
 "/Users/hsbt/.rbenv/versions/2.5.0-dev/lib/ruby/site_ruby/2.5.0",
 "/Users/hsbt/.rbenv/versions/2.5.0-dev/lib/ruby/site_ruby/2.5.0/x86_64-darwin17",
 "/Users/hsbt/.rbenv/versions/2.5.0-dev/lib/ruby/site_ruby",
 "/Users/hsbt/.rbenv/versions/2.5.0-dev/lib/ruby/vendor_ruby/2.5.0",
 "/Users/hsbt/.rbenv/versions/2.5.0-dev/lib/ruby/vendor_ruby/2.5.0/x86_64-darwin17",
 "/Users/hsbt/.rbenv/versions/2.5.0-dev/lib/ruby/vendor_ruby",
 "/Users/hsbt/.rbenv/versions/2.5.0-dev/lib/ruby/2.5.0",
 "/Users/hsbt/.rbenv/versions/2.5.0-dev/lib/ruby/2.5.0/x86_64-darwin17"]

先頭の、gem-rehash というパスは rbenv によって追加されているものです。RubyGems や Bundler を用いて gem をインストールした時に rbenv rehash をユーザーが実行しなくてもいいように、自動で実行するためのフックを入れるための rubygems_plugin.rb というファイルを追加しています。続いて追加されている、did_you_mean のパスについては Bundled gems で解説します。

gem-rehash, did_you_mean 以外のパスは lib 配下のパスを指していますが、site_ruby, vendor_ruby がどのように使われるかは今回は省略します。lib/ruby/2.5.0 に Ruby で書かれている Standard Liraries, lib/ruby/2.5.0/x86_64-darwin17 に C で書かれている Standard Libraries が保存され、ユーザーはここから net/httpopenssl のようなライブラリを呼び出すことができます。

この Standard Libraries が保存されているディレクトリは RubyGems や Bundler を利用した環境、特に Gemfile を用いてライブラリのバージョンの固定、または使うライブラリを限定した環境においても、$LOAD_PATH の最後にされるため、Ruby スクリプトならば何処からでも呼び出すことができます。以下は rails/rails のリポジトリで bundle exec の環境下で $LOAD_PATH を表示した例です。

~/D/g/r/rails (master) > bundle exec ruby -rpp -e 'pp $LOAD_PATH'
["/Users/hsbt/.rbenv/versions/2.5.0-dev/lib/ruby/gems/2.5.0/gems/bundler-1.15.4/lib",
 "/Users/hsbt/.rbenv/rbenv.d/exec/gem-rehash",
 "/Users/hsbt/.rbenv/versions/2.5.0-dev/lib/ruby/gems/2.5.0/bundler/gems/websocket-client-simple-e161305f1a46/lib",
 "/Users/hsbt/.rbenv/versions/2.5.0-dev/lib/ruby/gems/2.5.0/gems/websocket-1.2.4/lib",
 "/Users/hsbt/.rbenv/versions/2.5.0-dev/lib/ruby/gems/2.5.0/gems/concurrent-ruby-1.0.5/lib",
 (ここに200行あるため省略します)
 "/Users/hsbt/.rbenv/versions/2.5.0-dev/lib/ruby/gems/2.5.0/gems/rake-12.0.0/lib",
 "/Users/hsbt/.rbenv/versions/2.5.0-dev/lib/ruby/site_ruby/2.5.0",
 "/Users/hsbt/.rbenv/versions/2.5.0-dev/lib/ruby/site_ruby/2.5.0/x86_64-darwin17",
 "/Users/hsbt/.rbenv/versions/2.5.0-dev/lib/ruby/site_ruby",
 "/Users/hsbt/.rbenv/versions/2.5.0-dev/lib/ruby/vendor_ruby/2.5.0",
 "/Users/hsbt/.rbenv/versions/2.5.0-dev/lib/ruby/vendor_ruby/2.5.0/x86_64-darwin17",
 "/Users/hsbt/.rbenv/versions/2.5.0-dev/lib/ruby/vendor_ruby",
 "/Users/hsbt/.rbenv/versions/2.5.0-dev/lib/ruby/2.5.0",
 "/Users/hsbt/.rbenv/versions/2.5.0-dev/lib/ruby/2.5.0/x86_64-darwin17"]

最後に lib/ruby/2.5.0 が存在することを確認できると思います。この、Bundler の実行環境によらず require できるということがアプリケーションプログラマにとって、Standard Libraries の大きな特徴です。

発表では、上記以外の Standard Libraries の特徴や歴史、現在の状況についてご紹介します。

Default gems

次に解説するのは Default gems です。Default gems とは Starndard Libraries のうち、RubyGems を用いることで gem としてもインストールできるようにしたライブラリです。Ruby のソースコードリポジトリに一定ルールでライブラリ名と同じ名前で gemspec ファイルを配置することで、Standard Libraries を Default gems として扱うことが可能です。例えば、openssl の場合、openssl.gemspec というファイルをリポジトリに追加しています。

https://github.com/ruby/ruby/blob/trunk/ext/openssl/openssl.gemspec

このように gemspec ファイルを配置することで、Ruby のインストーラは Standard Libraries でありながらも、gemspec を用いて RubyGems でインストールされた gem のようにファイルを配置します。Default gems としてインストールされた Standard Libraries は以下のように gem list コマンドを実行した際に "default" という文字列が表示されます。

~ > gem list | grep default
bigdecimal (default: 1.3.2)
bundler (default: 1.15.4)
cmath (default: 0.0.1)
csv (default: 0.0.1)
date (default: 0.0.1)
dbm (default: 0.5.1)
digest (default: 0.1.0)
etc (default: 0.2.1)
fcntl (default: 0.0.1)
fiddle (default: 1.0.0.beta1)
fileutils (default: 0.7.2)
gdbm (default: 2.0.0.beta1)
io-console (default: 0.4.6)
ipaddr (default: 1.0.0)
json (default: 2.1.0)
openssl (default: 2.1.0.beta1)
psych (default: 3.0.0.beta3)
rdoc (default: 6.0.0.beta1, 5.1.0)
scanf (default: 0.0.1)
sdbm (default: 0.0.1)
stringio (default: 0.0.1)
strscan (default: 0.0.1)
webrick (default: 1.4.0.beta1)
zlib (default: 0.0.1)

Default gems は gemspec ファイルを用いた RubyGems への変更だけとなるので、 Standard Libraries と同じように RubyGems や Bundler の環境に左右されずに何処からでも呼び出すことができます。さらに Default gems は RubyGems を用いてインストールもできるため、古い安定バージョンの Ruby でも gem update openssl などを実行することで新しい実装の openssl ライブラリを利用できるというメリットもあります。

しかし、この Standard Libraries としてのライブラリと RubyGems に登録する gem としてのライブラリの両方を開発するのは、簡単なことではありません。例えば、Standard Libraries の場合はリリースサイクルは Ruby インタプリタのリリースと同時期の1年に1回、かつバックポートはブランチメンテナが行うため、ライブラリの開発にだけ集中できますが、Default gems の場合はライブラリのメンテナが gem のリリースも行う必要があります。

発表では Default gems の仕組み、現状、Pros/Cons についてより詳細な内容をご紹介します。

Bundled gems

最後に Bundled gems です。これは Standard Libraries や Default gems とは大きく違い、初期状態では $LOAD_PATH に含まれない、RubyGems で普通にインストールした gem と同じ状態のライブラリです。すなわち、Bundled gems でインストールされるライブラリ(gem)は、Ruby 開発チームが Ruby をインストールした初期状態でユーザーに使って欲しい、という gem です。

それでは先ほど $LOAD_PATH に含まれていた did_you_mean はなぜ何も設定しなくても読み込まれていたのでしょうか? これは did_you_mean を Bundled gems に追加するときに Matz ことまつもとさんから Ruby ユーザーにとって did_you_mean は最初から有効になっていた方が便利なはず、という意向を受けて、 gem としてインストールされている場合は読み込むようにしたという経緯があります。

さて、Bundled gems は普通にインストールした gem と同じ、ということから、アンインストールもできますし、RubyGems や Bundler から見ると通常の gem でしかないので、Gemfile に追加しなくては bundle exec などで参照できない、という制約があります。

発表では、なぜこのような Bundled gems という仕組みができたのか、そして Bundled gems が解決したもの、現在の問題などについて紹介します。

まとめ

以上、Ruby の標準添付ライブラリの現状について、添付形式の違いについて解説を行いました。発表では、添付形式以外の視点で以下のようなトピックについてもご紹介します。

  • Gemification は標準添付ライブラリをどう変えるのか
  • Default gems と Bundled gems は Ruby ユーザーのプログラミング体験にどのような変化を与えるのか
  • RubyGems と Bundler の将来はどうなるのか
  • Ruby 3 では、標準添付ライブラリはどうなるのか

上記のようなトピックに興味がある方は 1 日目 9/18(月) 14:40-15:20 にホール・ダリアへお越しいただけると嬉しいです。

PR

また、私が勤務している GMO ペパボは、RubyKaigi の Water スポンサー、撮影スポンサーとして協賛します。会期中、喉が渇いた方は休憩所で水を飲みに来ていただければと思います。また、企業ブースも設営予定ですので、 @hsbt の発表内容への質問や、ペパボという会社に興味を持っている方はお気軽にお越しください。

ペパボ水正面ペパボ水背面

それはみなさん広島で会いましょう!