🏯

RubyKaigi 2023参戦のためにRuby 3.2にバージョンアップしました

はじめに

Leaner 購買開発チームの RKTMcobachie です。

いよいよ RubyKaigi 2023 の開催が迫ってきましたね!

https://rubykaigi.org/2023/

Rubyist との交流が楽しみですが、そのためには我々にとって超えないといけない壁がありました。

Leaner 購買では Ruby がまだ 3.0 系だったのです(最新はご存知の通り 3.2 系)。

せっかくの RubyKaigi なので、3.2 系のいろいろな話を吸収して、帰ったらすぐにプロダクトで試したい。

ということで急遽 Ruby を最新化する活動を始めました。

Ruby 3.1へ上げる

Ruby 3.1 に上げたところ何箇所かエラーや警告が出ました。その原因と解決方法について記載します。

NameError: uninitialized class variable @@schemes in URI Did you mean? scheme_list

rake aborted!
NameError: uninitialized class variable @@schemes in URI
Did you mean?  scheme_list
/usr/local/bundle/gems/data_uri-0.1.0/lib/data_uri/uri.rb:64:in '<module:URI>'
/usr/local/bundle/gems/data_uri-0.1.0/lib/data_uri/uri.rb:1:in '<main>'

data_uri gem が Ruby 3.1 の変更に対応していなかったため発生したエラーでした。

https://github.com/dball/data_uri/pull/10

既存コードを確認すると、利用していた機能は data_uri gem のごく一部(content data の参照のみ)でした。

# 既存コードの利用例
uri = URI::Data.new(base64_data)
filename = "#{uri.content_type.split('/').last}"
do_something(io: StringIO.new(uri.data, 'rb'), filename:)

この機会に data_uri への依存をやめ、下記のようにインターフェースを保ちつつ、独自に実装を書き換えました。(Stack Overflow の実装を参考にしました。)

module URI
  class Data
    REGEXP = %r{\Adata:([-\w]+/[-\w+.]+)?;base64,(.*)}m

    def initialize(uri)
      data_uri_parts = uri.match(REGEXP) || []

      @content_type = data_uri_parts[1]
      @data = Base64.decode64(data_uri_parts[2])
    end
  end
end

LoadError: libruby.so.3.0: cannot open shared object file: No such file or directory - xxx

開発環境を Docker 化していると起こりがちな問題のようです。
コンテナ内で gem pristine --all すると解決できました。

docker compose run {コンテナ名} sh -c "gem pristine --all"

今回初めて gem pristine コマンドを知ったのですが、コマンドリファレンス によると、「キャッシュされた gem とインストールされた gem を比較し、差分があればキャッシュされた gem に戻す(pristine=手つかずの状態にする)」コマンドとのこと。

Calling DidYouMean::SPELL_CHECKERS.merge!(error_name => spell_checker)' has been deprecated. Please call DidYouMean.correct_error(error_name, spell_checker) instead.

最後は下記の警告の解消です。

Calling 'DidYouMean::SPELL_CHECKERS.merge!(error_name => spell_checker)' has been deprecated. Please call 'DidYouMean.correct_error(error_name, spell_checker)' instead.

RubyGems の下記 issue の通り、bundle update --bundler で解消できました。

https://github.com/rubygems/rubygems/issues/5234

あとは動作確認して、CI が通ることを確認して、リリース!

ハマるところが多かったのですが、無事 Ruby 3.1 へ上げることができました。

Ruby 3.2へ上げる

続いて Ruby 3.2(2023 年 4 月時点の最新バージョン v3.2.2)に上げていきます。

Ruby 3.2.2 にバージョンを切り替えて RSpec を実行すると、数箇所で以下のエラーが発生しました。

ArgumentError:
  wrong number of arguments (given 2, expected 1)

調査したところ、以下の issue に記載されている rspec-mocks の問題でした。

https://github.com/rspec/rspec-mocks/issues/1512

Ruby 3.2 でキーワード引数の仕様が変わったことにより、モックの with などのメソッドでキーワード引数がうまく渡せなくなったという不具合でした。

rspec-mocks v3.12.2 でこの問題が修正されていたので、rspec-mocks を含む rspec 関連 gem のバージョンをアップデートすることで解決しました。

$ bundle update rspec

こちらも動作確認と CI チェックを経て、無事に本番環境へリリースしました。

Leaner 購買はローンチしたばかりの新しいサービスで、RSpec などの自動テストを意識して開発しています。
そのおかげで、Ruby のバージョンアップに伴って発生した問題をすぐに検出でき、スムーズにバージョンを上げることができました。
テストは大切ですね。

最後に

Leaner 購買では、RubyKaigi 2023 に向けて Ruby 3.2 へのバージョンアップを行い、自信を持って Ruby の最新情報にアクセスできる環境を整えることができました。

これによってさらに RubyKaigi 2023 への期待が高まっています。

Leaner Technologies は RubyKaigi 2023 に Ruby Sponsor として協賛しています。

また、多くのエンジニアがオフライン・オンラインで参加予定です。世界中の Rubyists と松本でお会いできるのを楽しみにしています。

リーナーテックブログ

Discussion