RailsアプリケーションのRuby 3.0への展望

パッチ会や地域 Ruby コミュニティなどで集めた知見を元に、勤務先の永和システムマネジメントなんかで度々話している表題についてテキスト化しておく。

TL;DR

  • Ruby 2.8.0 の開発が始まっているが、それは 2020 年のどこかで Ruby 3.0 になるらしい
  • Ruby 3.0 ではキーワード引数 (以下 kwargs) の分離という破壊的変更があり、Ruby 2.7 系は事実上の移行パスバージョン的な位置付けになるだろう
  • 2020年1月8日の現時点では、Ruby 2.7 の kwargs の分離警告について対応された安定版の Rails はなく、周辺 Gem も WIP なので OSS エコシステムに参加していくと良い

2.8.0 (tentative; to be 3.0.0) development has started

2019年の ruby/ruby での matz のコミットです。

commit 537a1cd5a97a8c5e93b64851abaab42812506f66
Author: Yukihiro "Matz" Matsumoto <matz@ruby.or.jp>
Date:   Thu Dec 26 10:55:58 2019 +0900

    2.8.0 (tentative; to be 3.0.0) development has started.
---
 include/ruby/version.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/ruby/version.h b/include/ruby/version.h
index 64c5c614e0..25a961566b 100644
--- a/include/ruby/version.h
+++ b/include/ruby/version.h
@@ -31,7 +31,7 @@

 /* API version */
 #define RUBY_API_VERSION_MAJOR 2
-#define RUBY_API_VERSION_MINOR 7
+#define RUBY_API_VERSION_MINOR 8
 #define RUBY_API_VERSION_TEENY 0
 #define RUBY_API_VERSION_CODE (RUBY_API_VERSION_MAJOR*10000+RUBY_API_VERSION_MINOR*100+RUBY_API_VERSION_TEENY)


commit 3a0471faa0d383392ba05b3a6409b973b7b009d1
Author: matz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
Date:   Tue Dec 25 13:45:17 2018 +0000

    version.h (RUBY_VERSION): 2.7.0 development has started.

2.8.0 (tentative; to be 3.0.0) development has started. とのことで、暫定的に 2.8.0 というナンバリングで開発が開発されているものの、これが 3.0.0 になるようです。

kwargs の分離

公式エントリに Separation of positional and keyword arguments in Ruby 3.0 として記されているとおり、Ruby 3.0 での破壊的変更として kwargs の分離がされる。それに向けて Ruby 2.7 では以下のような非推奨警告がされる。

.../publicsuffix-ruby/lib/public_suffix/list.rb:51: warning: Using the last argument as keyword parameters is deprecated; maybe ** should be added to the call
.../publicsuffix-ruby/lib/public_suffix/list.rb:69: warning: The called method `parse' is defined here```

Ruby 2.8.0-dev では警告ではなく ArgumentError が起きるように本対応が入っている。

github.com

例えば上記警告はこのようなエラーになる。

Error:
AcceptanceTest#test_ignore_private:
ArgumentError: wrong number of arguments (given 2, expected 1)
    /Users/koic/src/github.com/weppos/publicsuffix-ruby/lib/public_suffix/list.rb:69:in `parse'
    /Users/koic/src/github.com/weppos/publicsuffix-ruby/lib/public_suffix/list.rb:51:in `default'
    /Users/koic/src/github.com/weppos/publicsuffix-ruby/lib/public_suffix.rb:69:in `parse'
    /Users/koic/src/github.com/weppos/publicsuffix-ruby/lib/public_suffix.rb:143:in `domain'
    /Users/koic/src/github.com/weppos/publicsuffix-ruby/test/acceptance_test.rb:105:in `block in test_ignore_private'
    /Users/koic/src/github.com/weppos/publicsuffix-ruby/test/acceptance_test.rb:101:in `each'
    /Users/koic/src/github.com/weppos/publicsuffix-ruby/test/acceptance_test.rb:101:in `test_ignore_private'

このようなエラーが起きている Gem をメンテナーやアーリーアダプターが対応してまわっているのが、現在のエコシステムのステータス。

このエラー例は ruby-head (Ruby 2.8) のテストが落ちていた addressable という Gem から依存されている publicsuffix-ruby という Gem でのこと。依存 Gem が対応していないと芋づる式にアプリケーションでもエラーが起きることになる。当然パッチがあたったあと手に届くため rubygems.org でパッケージ公開される必要がある。

すでに対応するための PR が出ていたので以下のイシューで、リリースへのトスを上げていた。

github.com

Rails での kwargs 分離への対応

Ruby の仕事で Web を書く場合に使われているだろう Rails フレームワークの話。

Rails での kwargs 分離への対応について、kamipo さんや amatsuda さんなどが Rails の master ブランチや Rails からの依存 Gem に対して進めてくれている。注意点として master ブランチはまだリリースプランの公開されていない開発版の Rails 6.1 を指している。これはローンチしている一般的なサービスで github オプションを指定しての本番投入がされているものではないと思う。

ということで巷の Rails アプリケーションがもちいている最新の安定版は十中八九 Rails 6.0 となるだろう。Rails 6.0 は 6-0-stable というブランチでメンテナンスがされており、master からそちらにバックポートがされる必要がある。当然 master との乖離があるためバックポートがどうなるかという話があるが、以下の PR がマージされていくつかのコンポーネントでのバックポートが進んでいる。

github.com

将来的にバックポートが完遂されれば Ruby 2.7 での警告が消えて、Rails 6.0 系についても Ruby 3.0 へのサポートがされていく未来が見えてくる。A Light in the Black.

一方で Rails 5.2 系へのバックポートはされないようで、例えば Oracle enhanced adapter でも Rails 5.2 ではサポートされないことを yahonda さんより回答されている。

github.com

つまり公式として Rails 5.2 系では Ruby 3.0 はサポートされないことが意味される。

Rails 5.1 系はすでにセキュリティメンテナンスもされていないので、そもそも対象とならない。

guides.rubyonrails.org

私の考える RubyRails のアップグレード

いずれにせよ Rails 5.2 以下を使っているようであれば、なにはともあれ Rails 6.0 までアップグレードをするのが先決。

Ruby に関しては最新の安定版 Ruby である Ruby 2.6 が Ruby 2 系における最後の警告なし互換バージョンになるだろう。Rails フレームワークが落ち着くまでは、それで運用することになりそう (Ruby 2.7 で導入された ruby -W:no-deprecated を使うという手もあるが、警告に蓋をするのは本筋ではないだろう) 。

その裏でローカル開発では Ruby 2.7 を使って kwargs 分離の非推奨警告を対応してまわることになると思う (当然 CI はランタイムに合わせた Ruby のバージョンになる) 。対応方法は、公式エントリ など見て各自がんばってほしい。個人的には delegate :type_to_sql, to: :conn のような delegate を介した kwargs の分離への警告は、メソッド定義と delegate 宣言の行が組み合わせとして示されるので、delegate の呼び出し場所を直す必要がある場合に手間取ったりした。

Ruby 2.7 で kwargs の分離の警告が消えたら Ruby 2.8 つまり Ruby 3.0 へのアップグレード準備の進捗はまずまずなのではないかと推測する。Ruby 1.8 から Ruby 1.9 にアップグレードするとき文字列のエンコーディングまわりで対応を要した記憶があるが、Ruby 1.9 に上げておくと Ruby 2.0 へのジャンプはスムースだった。いちおうその経験を裏打ちとして Ruby 2.7 は事実上の移行バージョンになると思う。

今日からやれること

そうは言ってもまだ Gem のエコシステムの方の対応が WIP だったりするので、仕事で使っている OSS への対応をするのが現状だと思う。例えば Gemfile.lock に記されている Gem など見てまわるのは初手にできるかもしれない。

このエントリのまとめは kamipo さんのツイートに集約される。

amatsuda さんと Rails / OSS パッチ会というのを開催しているので、そういった場なども活用されたい。

blog.agile.esm.co.jp