enpayのRubyが3.1.0にアップデートしました🎉
💎

enpayのRubyが3.1.0にアップデートしました🎉

こんにちは、エンジニアの 森塚(@sanfrecce_osaka) です。

酢昆布とか梅干しとか酸っぱいものが好きなんですが一度にたくさん食べすぎると知覚過敏になるということを最近知りました。

さてエンペイでは技術的負債が溜まらないよう、利用している言語やライブラリのアップデートを定期的に行っています。サーバーサイドのライブラリに関しては dependabot を利用して毎スプリント(エンペイでのスプリント周期は1週間)、タスクを積んで対応しています。(フロントエンドに関してはしばらく滞っているのでそこは今後の課題ですね 😅 )

そんな中、2022年2月17日 に enpay の Ruby のバージョンが 3.1.0 に上がりました 🎉 (主に対応してくれた @hoguccさん thx ‼️ )

この記事ではバージョンアップ時に対応が必要だったことやバージョンアップによって受けられた恩恵を紹介していこうと思います。

バージョンアップ時に必要だった対応

エンペイでは最もインパクトの大きい 3.0 へのバージョンアップを終えていたということもあり、大きな修正が必要な対応やクリティカルな問題は発生しませんでした。

メール関連の Gem

Ruby3.1.0 ではいくつかの Gem が default gem から bundled gem に変更になりました。

これらのうちメール関連の Gem (net-pop, net-imap, net-smtp)は actionmailer と actionmailbox の依存 Gem (正確には actionmailer と actionmailbox が依存している mail の依存 Gem)のため、Rails のバージョンが 6.1 以下の場合に net-pop や net-imap、net-smtp を読み込もうとした時点で LoadError が発生します。

この現象は Rails7.0 では https://github.com/rails/rails/pull/44083 で修正されているのですが、Pull Request の description にある通り Rails6.1 にはバックポートされていないためワークアラウンドな対応として Gemfile に net-pop、net-imap、net-smtp を追加しました。

psych

Ruby3.1 では psych のバージョンが 3 から 4 にアップデートされました。

psych は YAML を読み書きをする際に使用されるライブラリで Ruby の yaml はこの psych に依存しています。

ちなみに

この psych のバージョンアップは大きめの非互換な変更があり、アプリケーション側とライブラリ側どちらもこの非互換な変更に対応している必要があります。

変更の詳細に関しては本記事では詳細に説明しないため、以下も併せて読んでもらえると 🙇

プロと読み解く Ruby 3.1 NEWS - クックパッド開発者ブログ

技術部の笹田(ko1)と遠藤(mame)です。クックパッドで Ruby (MRI: Matz Ruby Implementation、いわゆる ruby コマンド) の開発をしています。お金をもらって Ruby を開発しているのでプロの Ruby コミッタです。 本日 12/25 に、ついに Ruby 3.1.0 がリリースされました( Ruby 3.1.0 リリース )。今年も Ruby 3.1 の NEWS.md ファイルの解説をします。NEWS ファイルとは何か、は以前の記事を見てください。 本記事は新機能を解説することもさることながら、変更が入った背景や苦労などの裏話も記憶の範囲で書いているところが特徴です。 今回リリースする Ruby 3.1 は総論として、Ruby 3.0との互換性を重視したリリースとなっています。 つまり、あまり大きな非互換はありません。 比較的アップグレードしやすいと思いますので、みなさん是非試してみてください。 ちなみに、Ruby 2.6はあと4ヶ月でEOL(サポート終了)で、Ruby 2系列最後の2.7も1年4ヶ月でEOLになると思われます。 月日が立つのは早いですね。 Ruby 3.1 の目玉として、次のようなものがあげられています。 ハッシュリテラルやキーワード引数の省略記法の導入 新しいJITコンパイラであるYJITの導入による性能向上 開発環境の向上 デバッガの刷新 エラー箇所に下線をひく error_highlight の導入 IRB のオートコンプリートとドキュメント表示 本記事では、これらを含めて NEWS ファイルにあるものをだいたい紹介していきます。 Values in Hash literals and keyword arguments can be omitted.

プロと読み解く Ruby 3.1 NEWS - クックパッド開発者ブログ
Ruby の YAML.load が非互換になる(かもしれない) - Secret Garden(Instrumental)

タイトルは釣りっぽいんですが Psych v4.0.0 で『 Psych.load が Psych.safe_load を使用するようになった』事で普段利用している YAML.load や YAML.load_file が今後非互換になってしまう、という話です。 この変更により今まで読み込むことができていた YAML ファイルが今後読み込みエラーになる可能性があります。 先にまとめだけ書いておくと Psych v4.0.0 で YAML.load が非互換になる なので既存の YAML データが読み込めずにエラーになる可能性がある もし急に YAML データが読み込めなくなったら Psych のバージョンを確認しよう 回避する場合は YAML.unsafe_load などが利用できる また、この記事の内容は記事を書いた当時の話なので今後変わっているかもしれないので注意してください。 NOTE: これは Ruby 本体の話というよりは『 Psych という gem が非互換になった』という話なので使用する Ruby のバージョン云々というよりかは『どの Psych のバージョンを使用するのか』という話になってきます。 Psych は Ruby 本体の default

Ruby の YAML.load が非互換になる(かもしれない) - Secret Garden(Instrumental)
Ruby の Psych.safe_load(YAML.safe_load)の引数が Psych v4.0.0 から非互換になる - Secret Garden(Instrumental)

さてさて、先日 YAML.load が非互換になる話を書きました。 その時に Psych.safe_load をいろいろと触ってたのですがその中で Psych.safe_load の引数もバージョンによって変わっていることに気づいたので書き溜めておきます。 先にまとめだけを書いておくと現状はこういう状況になっています。 Psych v3.1.0 (Ruby 2.5) 未満 -> Psych.safe_load はオプション引数だけを受け取る Psych v3.1.0 (Ruby 2.6) 以降 -> Psych.safe_load はオプション引数とキーワード引数を受け取る-w を付けるとオプション引数を使った時に警告が出る Psych v4.0.0 (Ruby は未定) 以降 -> Psych.safe_load はキーワード引数だけを受け取る ちなみに Psych は YAML のバックエンド実装なので YAML.safe_load も同様の問題になります。 Psych v3.1.0 未満では Psych.safe_load はオプション引数だけを受け取ります。 def safe_load(yaml, whitelist_classes =

Ruby の Psych.safe_load(YAML.safe_load)の引数が Psych v4.0.0 から非互換になる - Secret Garden(Instrumental)

エンペイでは今回はワークアラウンドな対応として一旦 Gemfile で psych のバージョンを 4.0.0 未満となるようにして対応と影響の確認を後回しにすることにしました。

gem 'psych', '< 4.0.0'

これは Rails7.0 へのアップデート時に他のライブラリのアップデートやしっかりめの QA も行うので、このときに一緒にやってしまおうという判断です。

余談

CircleCI のイメージの変更

Ruby3.1 とは直接関係はない話ではあるのですが、一緒に書いておきます。

エンペイでは CI は CircleCI を利用していますがこれまで利用していた CircleCI のイメージが 2021/12/31 で廃止されていました。

CircleCI のビルド済み Docker イメージ

Last updated * Reading time プレフィックスが「 circleci / 」のレガシーイメージは、 2021 年 12 月 31 日に廃止 されます。 ビルドを高速化するには、 次世代の CircleCI イメージ を使ってプロジェクトをアップグレードしてください。 This document provides information about pre-built CircleCI images (convenience images) and a listing by language, service type, and tags. CircleCI では、すぐに使える Docker イメージを多数提供しています。 These images are typically extensions of official Docker images, and include tools especially useful for CI/CD.

エンペイでの対応としては公式のマイグレーションガイドにある通り、CircleCI のイメージを prefix が cimg の次世代版に置き換えるだけで済みました。

次世代 CircleCI イメージへの移行

Last updated * Reading time 2020 年より、CircleCI では CircleCI イメージの次世代版の展開を開始しました。 これらのイメージは、 CircleCI 2.0 の発表時にリリースされた従来の CircleCI イメージに代わるものです。 次世代版は CI/CD 環境に合わせてゼロから設計されており、 従来よりもスピードと効率、そしてなによりも信頼性が大きく向上しています。 次世代 CircleCI イメージの特徴について詳しくは、 こちらのブログ記事 をご覧ください。 従来イメージが今後廃止されることに伴い、ここでは新しいイメージへの移行プロセスについて説明します。 従来のイメージから次世代版に移行するには、名前空間を変更する必要があります。 イメージの Docker 名前空間について、従来のものはすべて circleci でしたが、次世代イメージでは cimg に変わります。 たとえば、従来の Ruby および Python のイメージを次世代版に移行するには、それぞれ次のように変更します。 - circleci/python:3.8.4 + cimg/python:3.8.4 既存のイメージについて、今後いくつかの変更が行われる予定です。 以下のイメージは廃止され、次世代イメージへの置き換えは行われません。 buildpack-deps イメージを現在使用している場合は、新しい CircleCI ベース イメージ

Ruby3.1.0 に上がった恩恵

error_highlight

error_highlight は Ruby3.1 から入った機能で、NameError や NoMethodError が発生した場所を以下のように highlight してくれる機能です。

% ruby -e "1.time {}"                                                                                                                      [7:20:43]
-e:1:in `<main>': undefined method `time' for 1:Integer (NoMethodError)

1.time {}
 ^^^^^
Did you mean?  times

機能の詳細に関しては以下の記事で作者の 遠藤さん(@mametter) が解説してくれているのでそちらも併せて読んでいただけると 🙇

Ruby 3.1はエラー表示をちょっと親切にします - クックパッド開発者ブログ

こんにちは、ruby-devチームの遠藤(@mametter )です。 Among Usというゲームをやってるのですが、友達が少なくてあまり開催できないのが悩みです。 今日は、Ruby 3.1に導入される予定のerror_highlightという機能を紹介します。 NoMethodErrorが起きたとき、次のような表示が出るようになります。 どこのメソッド呼び出しで失敗したかが一目瞭然ですね。これだけの機能ですが、使ってみると意外と便利です。 この機能が本領を発揮するのは、RailsのparamsやJSONデータの取り扱いなどのときです。 たとえば json[:articles][:title]みたいなコードを書いて、 undefined method '[]' for nil:NilClassという例外が出たとします。 このとき、変数 jsonが nilだったのか、 json[:articles]の返り値が nil だったのかは、残念ながらコードだけ見ても判断できません。 特定するには、デバッグ出力を挟んで再実行する必要がありました。 error_highlightがあると、これがひと目で判別できます。 $ ruby test.rb test.rb:2:in ` ': undefined method `[]' for nil:NilClass (NoMethodError) title = json[:articles][:title] ^^^^^^^^^^^ ↑は、 jsonが nil だったケースです。 $ ruby test.rb test.rb:2:in ` ':

Ruby 3.1はエラー表示をちょっと親切にします - クックパッド開発者ブログ

この highlight はエラーメッセージの一部として出力されているので、Sentry でのエラーの通知内容にも含まれます。

なので通知されるエラーの調査が 3.0 までに比べて非常に捗るようになりました 🙌

ハッシュやキーワード引数の省略記法

Ruby3.1 ではハッシュやキーワード引数を利用する際にメソッド名や変数名と同じキー名を指定したい場合はキーに渡す値を省略できるようになりました。

JavaScript に慣れている方だとおなじみの記法ですね。

const func = ({ giraffe, elephant, rhinoceros }) => ({ giraffe, elephant, rhinoceros })

const giraffe = 'きりん'
const elephant = () => 'ぞう'
const rhinoceros = 'さい'

func({ giraffe, elephant, rhinoceros })

以前までは

def call_method(giraffe:, elephant:, rhinoceros:)
  {
    giraffe: giraffe,
    elephant: elephant,
    rhinoceros: rhinoceros,
  }
end

def giraffe = 'きりん'
def elephant = '象'

elephant = 'ぞう'
rhinoceros = 'さい'

call_method(
  giraffe: giraffe,
  elephant: elephant,
  rhinoceros: rhinoceros,
)
ちなみに

と同じ名前を指定したい場合何度も同じ名前を書かなければならず長い名前のキーだったりキーの数が増えれば増えるほど1行あたりの文字数が増えて改行が必要になりどんどん読みにくくなってしまっていましたが、Ruby3.1 からは

def call_method(giraffe:, elephant:, rhinoceros:)
  { giraffe:, elephant:, rhinoceros: }
end

def giraffe = 'きりん'
def elephant = '象'

elephant = 'ぞう'
rhinoceros = 'さい'

call_method(giraffe:, elephant:, rhinoceros:) # => {:giraffe=>'きりん', :elephant=>'ぞう', :rhinoceros=>'さい'}

と非常にスッキリ書けるようになりました。

メソッドの返り値も利用できるのが JavaScript と違うところですね。

なので以下のようなコードも動きます。

hash = { p: } # => { p: nil } ※Kernel.#p の返り値が nil のため

パターンマッチ

Ruby3.0 までは 1行パターンマッチ が experimental な機能だったため、1行パターンマッチ やパターンマッチを利用する右代入を使用した際に警告が出力されていました。

a = { b: 1, c: 2 } # => {:b=>1, :c=>2}
a in { b:, c: }
# (irb):2: warning: One-line pattern matching is experimental, and the behavior may change in future versions of Ruby!
a => { b:, c: }
# (irb):4: warning: One-line pattern matching is experimental, and the behavior may change in future versions of Ruby!

Ruby3.1 では 1行パターンマッチ が experimental でなくなり警告が出なくなったことでパターンマッチが晴れて Ruby の正式な言語機能となりました。

パターンマッチを利用する右代入はハッシュからまとめて値を取り出すときに、1行パターンマッチは条件判定を行いつつ変数への束縛を行いたいときに非常に便利だったんですが、これまでは利用すれば利用するほど警告が出てノイズになるのでプロダクションコードではなかなか気軽には利用できませんでした。

エンペイでは Ruby3.0 の頃からパターンマッチを利用していて(犯人は主に自分なのですが 😇 )アップデートが完了したことにより警告が出なくなったのでもう何の遠慮もなく使えます 🤩

そしてこれによる喜びの声がこちらになります 🤪

image

最後に

Ruby のバージョンアップが完了したので現在は Rails7.0 へのアップデートに取り組んでいます。

エンペイでは機能開発しつつライブラリのバージョンアップやリファクタリング等の改善作業も積極的に行っています。

まだまだやりたいことに対して手が足りていない状態なので、ご興味がある方は以下のリンクからぜひぜひご応募ください〜 📤

採用情報|株式会社エンペイ

お金のやりとりがスムーズではないことで生じる不便がある。 本当にお金を届けるべき人のところに、お金が届いていない。お金が理由で、やりたいことへのチャレンジができない。 私たちは、テクノロジーの力でそんなお金の流れを変え、未来を信じるだれもが自分の可能性を発揮することができる、やさしい社会をつくります。私たちが目指す社会を実現するために、仲間を探しています。

採用情報|株式会社エンペイ