Ruby
RubyDay 6

rubylang/all-ruby で ruby の全リリースの挙動を確かめる

Ruby Advent Calendar 2018 の 6 日目の記事です。
同じ内容で blog にも投稿 しています。

docker hub に rubylang/all-ruby というイメージがあって、 ruby の全リリースバージョンの挙動を確かめることができます。

ダウンロード

docker をインストールして使えるようにした後、普通に docker pull rubylang/all-ruby であらかじめダウンロードするか、初回実行時の自動ダウンロードに任せるかします。

Tags だと 3 GB と書いてありますが、手元のイメージを確認してみたところ、 10.2GB もあったので、ネットワークがしっかりしているところでダウンロードする方が良いでしょう。

% docker images | grep rubylang/all-ruby
rubylang/all-ruby                          latest              d6f0f07f0df6        4 weeks ago         10.3GB

実行例

./all-ruby コマンドで全てのリリースバージョンで実行して、実行結果が同じものはまとめて出力されます。

% docker run -it --rm rubylang/all-ruby ./all-ruby -e 'print("hello\n")'
ruby-0.49             hello
...
ruby-2.6.0-preview2   hello

出力が違う場合は別々に出てきますが、 pid などの違いはまとめられます。

% docker run -it --rm rubylang/all-ruby ./all-ruby -e 'p "hello"'
ruby-0.49             -e:1: syntax error
                  #<Process::Status: pid 7 exit 1>
ruby-0.50             -e:1: syntax error
                  #<Process::Status: pid 8 exit 1>
ruby-0.51             -e:1: undefined method `p' for "main"(Object)
                  #<Process::Status: pid 9 exit 1>
ruby-0.54             -e:1:in method `p': undefined method `p' for "main"(Object)
                  #<Process::Status: pid 10 exit 1>
ruby-0.55             -e:1: undefined method `p' for "main"(Object)
                  #<Process::Status: pid 11 exit 1>
...
ruby-0.76             -e:1: undefined method `p' for "main"(Object)
                  #<Process::Status: pid 20 exit 1>
ruby-0.95             -e:1: undefined method `p' for main(Object)
                  #<Process::Status: pid 21 exit 1>
ruby-0.99.4-961224    "hello"
...
ruby-2.6.0-preview2   "hello"

バージョンによる違いの例

Time#to_s

何度か書式が変わっていることがわかります。

% docker run -it --rm rubylang/all-ruby ./all-ruby -e 'print(Time.at(0))'
ruby-0.49             Thu Jan 01 00:00:00 UTC 1970
...
ruby-1.8.5-preview2   Thu Jan 01 00:00:00 UTC 1970
ruby-1.8.5-preview3   Thu Jan 01 00:00:00 +0000 1970
...
ruby-1.8.5-p231       Thu Jan 01 00:00:00 +0000 1970
ruby-1.8.6-preview1   Thu, Jan 01 1970 00:00:00 +0000
...
ruby-1.8.6-preview3   Thu, Jan 01 1970 00:00:00 +0000
ruby-1.8.6            Thu Jan 01 00:00:00 +0000 1970
...
ruby-1.8.7-p374       Thu Jan 01 00:00:00 +0000 1970
ruby-1.9.0-0          1970-01-01 00:00:00 +0000
...
ruby-2.6.0-preview2   1970-01-01 00:00:00 +0000

Array#filter

2.6 で追加されたメソッドが Array#filterがなかった をみて昔あったということを気づけたので確認してみたところ、 1.6 までの挙動と違う挙動で 2.6 に追加されていることがわかりました。

% docker run -it --rm rubylang/all-ruby ./all-ruby -e 'a=[1,2]; p a.filter{|x|x+1}'
(略)
ruby-1.1b7            [2, 3]
...
ruby-1.4.6            [2, 3]
ruby-1.6.0            -e:1: warning: Array#filter is deprecated; use Array#collect!
                      [2, 3]
...
ruby-1.6.8            -e:1: warning: Array#filter is deprecated; use Array#collect!
                      [2, 3]
ruby-1.8.0            -e:1: undefined method `filter' for [1, 2]:Array (NoMethodError)
                  #<Process::Status: pid 142 exit 1>
...
ruby-1.8.7-p374       -e:1: undefined method `filter' for [1, 2]:Array (NoMethodError)
                  #<Process::Status: pid 216 exit 1>
ruby-1.9.0-0          -e:1:in `<main>': undefined method `filter' for [1, 2]:Array (NoMethodError)
                  #<Process::Status: pid 217 exit 1>
...
ruby-2.6.0-preview1   -e:1:in `<main>': undefined method `filter' for [1, 2]:Array (NoMethodError)
                  #<Process::Status: pid 459 exit 1>
ruby-2.6.0-preview2   [1, 2]

nil の object_id

最初は 0 だったのがだんだん大きくなっていったようです。

% docker run -it --rm rubylang/all-ruby ./all-ruby -e 'print(nil.id)'
ruby-0.49             0
...
ruby-0.95             0
ruby-0.99.4-961224    2
...
ruby-1.1a5            2
ruby-1.1a6            4
...
ruby-1.8.2-preview3   4
ruby-1.8.2-preview4   -e:1: warning: Object#id will be deprecated; use Object#object_id
                      4
...
ruby-1.8.7-p374       -e:1: warning: Object#id will be deprecated; use Object#object_id
                      4
ruby-1.9.0-0          -e:1:in `<main>': undefined method `id' for nil:NilClass (NoMethodError)
                  #<Process::Status: pid 217 exit 1>
...
ruby-2.6.0-preview2   -e:1:in `<main>': undefined method `id' for nil:NilClass (NoMethodError)
                  #<Process::Status: pid 461 exit 1>
% docker run -it --rm rubylang/all-ruby ./all-ruby -e 'print(nil.object_id)'
(略)
ruby-1.6.8            -e:1: undefined method `object_id' for nil (NameError)
                  #<Process::Status: pid 142 exit 1>
ruby-1.8.0            4
...
ruby-1.9.3-p551       4
ruby-2.0.0-preview1   8
...
ruby-2.6.0-preview2   8

その他

docker run -it --rm rubylang/all-ruby /bin/bash で中に入って色々と調べることができます。

ヘルプ

引数なしで ./all-ruby を実行すると usage がでてきます。

% docker run -it --rm rubylang/all-ruby ./all-ruby
usage: all-ruby RUBY-ARGS
environment variables:
  ALL_RUBY_SINCE=ruby-1.4
  ALL_RUBY_SHOW_DUP=yes
  ALL_RUBY_BINS='ruby-2.1.10 ruby-2.2.10 ruby-2.3.7 ruby-2.4.4 ruby-2.5.1'
  ALL_RUBY_ADDBINS=./ruby       space-separated binaries to be run

docker run -it --rm rubylang/all-ruby -h のようなオプション指定は、その引数で ruby を実行するという意味になるので、 all-ruby 自体のオプションとしては扱わないようです。

環境変数指定

env コマンドを使って環境変数を設定して all-ruby を実行すると、例えば ruby 1.4.0 以降のみで実行などができるようです。

% docker run -it --rm rubylang/all-ruby env ALL_RUBY_SINCE=ruby-1.4 ./all-ruby -e 'p "hello"'
ruby-1.4.0            "hello"
...
ruby-2.6.0-preview2   "hello"

まとめ

複数の ruby のリリースバージョンの動作をまとめて確認できる docker イメージの rubylang/all-ruby を紹介しました。
サイズが大きいのでディスクに余裕のある環境だけに入れて、常用できるようにしておくと歴史的な調査などに便利です。