Ruby 3.1.0 preview1 でたよ

でました。
リリースノートはこちら。

rbenv を使っている方は、

$ rbenv install 3.1.0-preview1

してもらえるとローカルにインストールすることができます。
以下、気になった機能追加や変更点など。

新しい JIT コンパイラとして実験的に YJIT が追加された

Ruby 3.1 では新しい JIT コンパイラとして YJIT が追加されます。
YJIT はデフォルトでは有効になっていないので有効にする場合は Ruby のコマンドプションに --yjit を指定する必要があります。
YJIT を使用することで Rails のベンチが最大22%向上するらしいですね、すごい。
また現状 YJIT は macOSLinuxx86-64 環境でのみ対応しているらしいです。

新しいデバッガとして debug gem がバンドルされる

Ruby 3.1 から新しいデバッガとして debug gem がバンドルされます。
ここで説明するよりも RubyKaigi の内容を見てもらった方がよいと思います。

byebug のように端末で詳細なデバッグができる他 VSCodeChrome の devtools でもデバッグ操作ができます。
これはとにかく楽しみでしょうがないので早く使いたいです。
また Ruby 3.1 にバンドルされるようになるんですが Ruby 2.6 以上であれば

$ gem install debug

で debug gem を使用する事ができます。

列単位でエラー箇所を表示する error_highlight が追加

例えば次のようなコードでエラーになった時にどこでエラーになっているのか分かりづらい事があります。

ruby -e "{user:'homu'}[:ser][:name]"
-e:1:in `<main>': undefined method `[]' for nil:NilClass (NoMethodError)

error_highlight は次のようにどこでエラーになっているのかを表示してくれる機能になります。

$ RBENV_VERSION=3.1.0-preview1 ruby -e "{user:'homu'}[:ser][:name]"
-e:1:in `<main>': undefined method `[]' for nil:NilClass (NoMethodError)

{user:'homu'}[:ser][:name]
                   ^^^^^^^

これは普通に便利なので早くほしい。

Hash リテラルで参照する値がキー名と同じなら省略できる

これ!前からほしかったやつ!!!! Hash リテラルを定義する時に値を省略するとキーと同じ名前の変数やメソッドを参照するようになります。

def name
  "homu"
end

age = 42

# 値を省略するとその名前の変数やメソッドを参照する
# { id: 1, name: name, age: age } と同じ意味
homu = { id: 1, name:, age: }
pp homu
# => {:id=>1, :name=>"homu", :age=>42}

# Hash リテラルだけではなくてメソッドのキーワード引数としても渡せる
# pp(name: name, age: age) と同じ意味
pp(name:, age:)
# => {:name=>"homu", :age=>42}

パターンマッチの ^ が式を受け取るようになった

パターンマッチの ^ で直接式をかけるようになりました。
今までは以下のように変数に代入する必要があったんですが

# 一度変数に入れてから ^ で変数を参照する必要があった
range = Time.new(2010)..Time.new(2020)

case data
in { created_at: ^range }
end

Ruby 3.1 からは以下のように直接式を書くことができます。

case data
# ^ で直接式を書くことができるようになった
in { created_at: ^(Time.new(2010)..Time.new(2020)) }
end

これは普通に便利ですね。

1行パターンマッチが Experimental でなくなった

機能としては Ruby 3.0 から実験的に実装されていたんですが Ruby 3.1 からは実験的でなくなりました。
なので次のようなコードを書いても Experimental Warning がでなくなります!!

# 3.0 : warning: One-line pattern matching is experimental, and the behavior may change in future versions of Ruby!
# 3.1 : no warning
user = { name: "homu", age: 14 }
user => { name:, age: }

p name # = "homu"
p age  # = 14

refine 内での include / prepend が非推奨になり変わりに import_methods が追加された

これは別途まとめたいと思うんですが refine 内で include / prepend したときの挙動が意図しないことが多かったので非推奨になり、変わりに import_methods という機能が追加されました。
今までだと例えば複数のクラスで共通のメソッドを定義したい場合に以下のように include していました。

using Module.new {
  module Twice
    def twice
      self + self
    end
  end

  refine String do
    include Twice
  end

  refine Integer do
    include Twice
  end
}

pp "homu".twice
pp 42.twice

Ruby 3.1 からは以下のように import_methods を使うことが推奨されます。

using Module.new {
  module Twice
    def twice
      self + self
    end
  end

  refine String do
    import_methods Twice
  end

  refine Integer do
    import_methods Twice
  end
}

# 使い方は一緒
pp "homu".twice
pp 42.twice

大きな違いとしては『 include する Module のメソッドが別のメソッド呼び出す時の挙動』が違います。

using Module.new {
  module Twice
    def twice
      self + self
    end

    def double
      twice
    end
  end

  refine String do
    import_methods Twice
  end

  refine Integer do
    include Twice
  end
}

# OK : Twice#double 内から Twice#twice を呼び出せる
p "homu".twice

# NG : Twice#double 内から Twice#twice が呼び出せない
p 42.double

既存のコードが非互換になってしまうのはちょっとつらいですが使い勝手はこっちのほうが圧倒的によいので早く移行したいですねえ。
両コードをサポートする場合どうするのがよいだろうか。

と、言う感じで Ruby 3.1 でも色々と機能が追加されるので楽しみですね!