Ruby 3.1 に備えよう!

19.5K Views

December 17, 21

スライド概要

シェア

埋め込む »CMSなどでJSが使えない場合

関連スライド

各ページのテキスト
1.

Ruby 3.1 に備えよう! 銀座Rails#40

2.

自己紹介 名前:osyo Twitter : @pink_bangbi github : osyo-manga ブログ : Secret Garden(Instrumental) Rails エンジニア 好きな Ruby の機能は Refinements Ruby 3.1 で楽しみな機能は Hash の省略記法と debug.gem RubyKaigi Takeout 2021 Use Macro all the time ~ マクロを使いまくろ ~ Advent Calendar やってるよ! Ruby の TracePoint を使ってメソッド呼び出しをトレースしよう 一人 bugs.ruby Advent Calendar

3.

Ruby 3.1 に備えよう!

4.

!!!注意!!!

5.

!!!注意!!! 2021/12/17 時点の情報

6.

!!!注意!!! 2021/12/17 時点の情報 リリース時には挙動が 変わっているかもしれない

7.

静的解析

8.

TypeProf が IDE サポートを追加 TypeProf が実験的に IDE のサポートを追加 このサポートを利用する事で IDE 上で型情報を表示したりコード補完の恩恵を受ける事ができる LSP が対応しているエディタであれば利用可能 Vim でも使える 詳しくはこちらを参照 参照 TypeProf for IDE: Enrich Dev-Experience without Annotations by Yusuke Endoh - RubyKaigi Takeout 2021

9.

デバッガが追加 Ruby 3.1 では新しいデバッガとして debug.gem が追加される byebug のようなステップ実行が行うことができる VSCode などでのリモートデバッグ機能があり GUI 上でデバッグを行う事ができる 銀座Rails #38での debug.gem のデモが 作者のサイトで動画も公開されているのでぜひ見てもらいたい また Ruby 2.6 以降であれば `gem install debug` をすることで debug.gem を使用する事ができる 参照 README The Art of Execution Control for Ruby’s Debugger by Koichi Sasada - RubyKaigi Takeout 2021

10.

エラー箇所をハイライトする [Feature #17930] エラー箇所がハイライトされる機能が新しく実装された この機能はデフォルトで有効になっており `--disable-error_highlight` で無効にする事ができる 以下のようにエラーの列の位置がわかるようになった

11.

エラー箇所をハイライトする [Feature #17930] エラー箇所がハイライトされる機能が新しく実装された この機能はデフォルトで有効になっており `--disable-error_highlight` で無効にする事ができる 以下のようにエラーの列の位置がわかるようになった `json` が `nil` の場合 $ ruby test.rb test.rb:2:in `<main>': undefined method `[]' for nil:NilClass (NoMethodError) title = json[:article][:title] ^^^^^^^^^^

12.

エラー箇所をハイライトする [Feature #17930] エラー箇所がハイライトされる機能が新しく実装された この機能はデフォルトで有効になっており `--disable-error_highlight` で無効にする事ができる 以下のようにエラーの列の位置がわかるようになった `json` が `nil` の場合 $ ruby test.rb test.rb:2:in `<main>': undefined method `[]' for nil:NilClass (NoMethodError) title = json[:article][:title] ^^^^^^^^^^ `json[:article]` が `nil` の場合 $ ruby test.rb test.rb:2:in `<main>': undefined method `[]' for nil:NilClass (NoMethodError) title = json[:article][:title] ^^^^^^^^

13.

エラー箇所をハイライトする [Feature #17930] エラー箇所がハイライトされる機能が新しく実装された この機能はデフォルトで有効になっており `--disable-error_highlight` で無効にする事ができる 以下のようにエラーの列の位置がわかるようになった `json` が `nil` の場合 $ ruby test.rb test.rb:2:in `<main>': undefined method `[]' for nil:NilClass (NoMethodError) title = json[:article][:title] ^^^^^^^^^^ `json[:article]` が `nil` の場合 $ ruby test.rb test.rb:2:in `<main>': undefined method `[]' for nil:NilClass (NoMethodError) title = json[:article][:title] ^^^^^^^^ 参照:Ruby 3.1はエラー表示をちょっと親切にします - クックパッド開発者ブログ

14.

言語機能

15.
[beta]
Hash
の省略記法
[Feature
#14579]
Hash を定義する時に値を省略するとキーと同じ名前の変数やメソッドを参照する
や `foo(x:, y:)` が `{ x: x, y: y }` や `foo(x: x, y: y)` となる
同名の変数、メソッド、定数が参照される
`{ x:, y: }`

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}

参照:Ruby 3.1 で { a: a } が { a: } とかけるようになるらしい - Secret Garden(Instrumental)}

16.

YJIT が追加 [Feature #18229] Ruby 3.1 では新しい JIT コンパイラとして YJIT が追加された YJIT はデフォルトでは有効になっていないので有効にする場合は Ruby のコマンドプションに `--yjit` を 指定する必要がある YJIT を使用することで Rails のベンチマークが最大22%向上する また現状 YJIT は macOS と Linux の x86-64 環境でのみ対応している 参照 YJIT - Building a new JIT Compiler inside CRuby by Maxime Chevalier-Boisvert - RubyKaigi Takeout 2021

17.

パターンマッチの `^` が式に対応 [Feature #17411] パターンマッチの `^` は以下のように変数に代入する必要があった 一度変数に入れてから で変数を参照する必要があった # ^ range = Time.new(2010)..Time.new(2020) case data in { created_at: ^range } # data[:created_at] range end が 内であればここが呼ばれる

18.

パターンマッチの `^` が式に対応 [Feature #17411] パターンマッチの `^` は以下のように変数に代入する必要があった 一度変数に入れてから で変数を参照する必要があった # ^ range = Time.new(2010)..Time.new(2020) case data in { created_at: ^range } # data[:created_at] range end が 内であればここが呼ばれる Ruby 3.1 からは以下のように直接式を書くことができる で直接式を書くことができるようになった # ^ case data in { created_at: ^(Time.new(2010)..Time.new(2020)) } # data[:created_at] range end が 内であればここが呼ばれる

19.

パターンマッチの `^` が式に対応 [Feature #17411] パターンマッチの `^` は以下のように変数に代入する必要があった 一度変数に入れてから で変数を参照する必要があった # ^ range = Time.new(2010)..Time.new(2020) case data in { created_at: ^range } # data[:created_at] range end が 内であればここが呼ばれる Ruby 3.1 からは以下のように直接式を書くことができる で直接式を書くことができるようになった # ^ case data in { created_at: ^(Time.new(2010)..Time.new(2020)) } # data[:created_at] range end が 内であればここが呼ばれる こんな感じで n に束縛しつつ使用する事もできる Prime.each_cons(2).lazy.find_all{ _1 in [n, ^(n + 2)] }.take(3).to_a #=> [[3, 5], [5, 7], [11, 13]]

20.

パターンマッチの `^` が @変数などに対応 [Feature #17724] Ruby 3.0 ではパターンマッチの `^` はローカル変数のみ参照できた Ruby 3.1 からは `^` がインスタンス変数やクラス変数、グローバル変数を参照できるようになった @range = Time.new(2010)..Time.new(2020) case data in { created_at: ^@range } # data[:created_at] end が range 内であればここが呼ばれる

21.

匿名のブロック引数をフォワードする [Feature #11256] 匿名のブロック引数を別のメソッドへフォワードできるようになった def foo(a) yield a + a end def bar(&) # foo(2, &) end 自身のブロック引数を foo にフォワードする p bar { _1 } # => 2

22.

匿名のブロック引数をフォワードする [Feature #11256] 匿名のブロック引数を別のメソッドへフォワードできるようになった def foo(a) yield a + a end def bar(&) # foo(2, &) end 自身のブロック引数を foo にフォワードする p bar { _1 } # => 2 また `&` を省略する事はできない def foo(&) = bar(&) # OK def foo = bar(&) # NG

23.

匿名のブロック引数をフォワードする [Feature #11256] 匿名のブロック引数を別のメソッドへフォワードできるようになった def foo(a) yield a + a end def bar(&) # foo(2, &) end 自身のブロック引数を foo にフォワードする p bar { _1 } # => 2 また `&` を省略する事はできない def foo(&) = bar(&) # OK def foo = bar(&) # NG ブロックからは使えないぽい? def hoge; end # no anonymous block parameter proc { |&| hoge(&) }

24.
[beta]
1行パターンマッチが
Experimental
でなくなった
Ruby 3.0 から実験的に実装されていた1行パターンマッチが Ruby 3.1 から実験的でなくなった
user = { name: "homu", age: 14 }
# 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:, age: }
p name # = "homu"
p age # = 14

# 3.0 : warning: One-line pattern matching is experimental, and the behavior may change in future versions of Ruby!
# 3.1 : no warning
if user in { name: String, age: (..20) }
puts "OK"
end

25.

エンドレスメソッド定義でコマンドが対応 [Feature #17398] エンドレスメソッド定義の本体ではコマンドが対応していなかった コマンドとは `puts "Hello"` のような `()` がないメソッドの呼び出しなどを指す なので `def foo = puts "Hello"` がシンタックスエラーになっていた `def foo = puts("Hello")` だと OK Ruby 3.1 ではコマンドも本体にかけるようになった # Ruby 3.0 => syntax error, unexpected string literal, expecting `do' or '{' or '(' # Ruby 3.1 => no error def foo = puts "Hello"

26.

エンドレスメソッド定義でコマンドが対応 [Feature #17398] エンドレスメソッド定義の本体ではコマンドが対応していなかった コマンドとは `puts "Hello"` のような `()` がないメソッドの呼び出しなどを指す なので `def foo = puts "Hello"` がシンタックスエラーになっていた `def foo = puts("Hello")` だと OK Ruby 3.1 ではコマンドも本体にかけるようになった # Ruby 3.0 => syntax error, unexpected string literal, expecting `do' or '{' or '(' # Ruby 3.1 => no error def foo = puts "Hello" ただし、以下のような書き方だとパースできないので動かないので注意 # syntax error, unexpected string literal, expecting `do' or '{' or '(' private def foo = puts "Hello"

27.

`foo[0], bar.baz = a, b` の評価順が変更 [Bug #4443] Ruby の代入式の評価順は左から右に向かって評価される

28.

`foo[0], bar.baz = a, b` の評価順が変更 [Bug #4443] Ruby の代入式の評価順は左から右に向かって評価される なので以下のような式は foo[0] = bar

29.

`foo[0], bar.baz = a, b` の評価順が変更 [Bug #4443] Ruby の代入式の評価順は左から右に向かって評価される なので以下のような式は foo[0] = bar 1. `foo` が評価される

30.

`foo[0], bar.baz = a, b` の評価順が変更 [Bug #4443] Ruby の代入式の評価順は左から右に向かって評価される なので以下のような式は foo[0] = bar 1. `foo` が評価される 2. `bar` が評価される

31.

`foo[0], bar.baz = a, b` の評価順が変更 [Bug #4443] Ruby の代入式の評価順は左から右に向かって評価される なので以下のような式は foo[0] = bar 1. `foo` が評価される 2. `bar` が評価される 3. `foo` の `[]=` が評価される( `foo[0]=` )

32.

Ruby 3.1 では以下のような代入式の評価順が変わった foo[0], bar.baz = a, b

33.

Ruby 3.1 では以下のような代入式の評価順が変わった foo[0], bar.baz = a, b Ruby 3.0 の場合

34.

Ruby 3.1 では以下のような代入式の評価順が変わった foo[0], bar.baz = a, b Ruby 3.0 の場合 1. `a` が評価される

35.

Ruby 3.1 では以下のような代入式の評価順が変わった foo[0], bar.baz = a, b Ruby 3.0 の場合 1. `a` が評価される 2. `b` が評価される

36.

Ruby 3.1 では以下のような代入式の評価順が変わった foo[0], bar.baz = a, b Ruby 3.0 の場合 1. `a` が評価される 2. `b` が評価される 3. `foo` が評価される

37.

Ruby 3.1 では以下のような代入式の評価順が変わった foo[0], bar.baz = a, b Ruby 3.0 の場合 1. `a` が評価される 2. `b` が評価される 3. `foo` が評価される 4. `foo` の `[]=` が評価される( `foo[0]=` )

38.

Ruby 3.1 では以下のような代入式の評価順が変わった foo[0], bar.baz = a, b Ruby 3.0 の場合 1. `a` が評価される 2. `b` が評価される 3. `foo` が評価される 4. `foo` の `[]=` が評価される( `foo[0]=` ) 5. `bar` が評価される

39.

Ruby 3.1 では以下のような代入式の評価順が変わった foo[0], bar.baz = a, b Ruby 3.0 の場合 1. `a` が評価される 2. `b` が評価される 3. `foo` が評価される 4. `foo` の `[]=` が評価される( `foo[0]=` ) 5. `bar` が評価される 6. `bar` の `baz=` が評価される( `bar.baz=` )

40.

Ruby 3.1 では以下のような代入式の評価順が変わった foo[0], bar.baz = a, b Ruby 3.0 の場合 1. `a` が評価される 2. `b` が評価される 3. `foo` が評価される 4. `foo` の `[]=` が評価される( `foo[0]=` ) 5. `bar` が評価される 6. `bar` の `baz=` が評価される( `bar.baz=` ) Ruby 3.1 の場合

41.

Ruby 3.1 では以下のような代入式の評価順が変わった foo[0], bar.baz = a, b Ruby 3.0 の場合 1. `a` が評価される 2. `b` が評価される 3. `foo` が評価される 4. `foo` の `[]=` が評価される( `foo[0]=` ) 5. `bar` が評価される 6. `bar` の `baz=` が評価される( `bar.baz=` ) Ruby 3.1 の場合 1. `foo` が評価される

42.

Ruby 3.1 では以下のような代入式の評価順が変わった foo[0], bar.baz = a, b Ruby 3.0 の場合 1. `a` が評価される 2. `b` が評価される 3. `foo` が評価される 4. `foo` の `[]=` が評価される( `foo[0]=` ) 5. `bar` が評価される 6. `bar` の `baz=` が評価される( `bar.baz=` ) Ruby 3.1 の場合 1. `foo` が評価される 2. `bar` が評価される

43.

Ruby 3.1 では以下のような代入式の評価順が変わった foo[0], bar.baz = a, b Ruby 3.0 の場合 1. `a` が評価される 2. `b` が評価される 3. `foo` が評価される 4. `foo` の `[]=` が評価される( `foo[0]=` ) 5. `bar` が評価される 6. `bar` の `baz=` が評価される( `bar.baz=` ) Ruby 3.1 の場合 1. `foo` が評価される 2. `bar` が評価される 3. `a` が評価される

44.

Ruby 3.1 では以下のような代入式の評価順が変わった foo[0], bar.baz = a, b Ruby 3.0 の場合 1. `a` が評価される 2. `b` が評価される 3. `foo` が評価される 4. `foo` の `[]=` が評価される( `foo[0]=` ) 5. `bar` が評価される 6. `bar` の `baz=` が評価される( `bar.baz=` ) Ruby 3.1 の場合 1. `foo` が評価される 2. `bar` が評価される 3. `a` が評価される 4. `b` が評価される

45.

Ruby 3.1 では以下のような代入式の評価順が変わった foo[0], bar.baz = a, b Ruby 3.0 の場合 1. `a` が評価される 2. `b` が評価される 3. `foo` が評価される 4. `foo` の `[]=` が評価される( `foo[0]=` ) 5. `bar` が評価される 6. `bar` の `baz=` が評価される( `bar.baz=` ) Ruby 3.1 の場合 1. `foo` が評価される 2. `bar` が評価される 3. `a` が評価される 4. `b` が評価される 5. `foo` の `[]=` が評価される( `foo[0]=` )

46.

Ruby 3.1 では以下のような代入式の評価順が変わった foo[0], bar.baz = a, b Ruby 3.0 の場合 1. `a` が評価される 2. `b` が評価される 3. `foo` が評価される 4. `foo` の `[]=` が評価される( `foo[0]=` ) 5. `bar` が評価される 6. `bar` の `baz=` が評価される( `bar.baz=` ) Ruby 3.1 の場合 1. `foo` が評価される 2. `bar` が評価される 3. `a` が評価される 4. `b` が評価される 5. `foo` の `[]=` が評価される( `foo[0]=` ) 6. `bar` の `baz=` が評価される( `bar.baz=` )

47.

コアクラスの更新

48.

`private` などの戻り値の変更 [Feature #12495] の `#private` `#public` `#protected` `#module_function` の戻り値がレシーバからそのメソ ッドの引数に変更された `Module` class X def hoge; end def foo; end 引数をそのまま返す # private :hoge # Ruby 3.0 => X # Ruby 3.1 => :hoge 複数ある場合は配列を返す # private :hoge, :foo # Ruby 3.0 => X # Ruby 3.1 => [:hoge, :foo] 引数がない場合は # nil private # Ruby 3.0 => X # Ruby 3.1 => nil end を返す

49.

これは以下のようにメソッドをネストして呼び出す時に利用できる メソッド名を受け取ってなにかしら処理をするメソッド # def cached(name) return name end 化しつつ別のメソッドを呼び出す事ができる # private cached private def foo() end 非互換な変更になるので `private` の戻り値に依存しているコードは要注意

50.

アクセシビリティを判定するメソッドが追加 [Feature #11689] にそのメソッドのアクセシビリティを判定する `Method/UnboundMethod` `#protected?` が追加された トップレベルメソッドは暗黙的に private # NOTE: def hoge; end pp method(:hoge).private? pp method(:hoge).public? # => true # => false public :hoge pp method(:hoge).private? pp method(:hoge).public? # => false # => true `#public?` `#private?`

51.

※追記:この機能は Ruby 3.1 に入りませんでした `Class#descendants` が追加 [Feature #14394] `Class#descendants` は継承されている全てのクラスの一覧を取得するメソッド class A; end class B < A; end class C < B; end クラスがどのクラスで継承されているのかを返す # p A.descendants p B.descendants p C.descendants #=> [B, C] #=> [C] #=> []

52.

`Class#subclass` `Class#subclass` class class class class が追加 [Feature #18273] は直接継承されているクラスの一覧を取得するメソッド A; end B < A; end C < B; end D < A; end A.subclasses B.subclasses #=> [D, B] #=> [C] C.subclasses #=> []

53.

`Module#prepend` の挙動が調整 [Bug #17423] Ruby 3.0 では継承リスト周りの処理が色々と改善された その結果 `#prepend` が意図する挙動をしていないケースがあった module M1; end module M2; end class A; include M2; end M2.prepend M1 A.prepend M1 # p # # に しているのに反映されてないように見える A prepend M1 A.ancestors 2.7 => [M1, A, M2, Object, Kernel, BasicObject] 3.0 => [A, M1, M2, Object, Kernel, BasicObject]

54.

これの対処として Ruby 3.1 では `A.prepend M1` が反映されるようになった Ruby 2.7 ~ 3.1 で全ての挙動が違うので要注意 Ruby 3.1 だと `M1` が複数ある点も注意 module M1; end module M2; end class A; include M2; end M2.prepend M1 A.prepend M1 p A.ancestors # 2.7 => [M1, A, M2, Object, Kernel, BasicObject] # 3.0 => [A, M1, M2, Object, Kernel, BasicObject] # 3.1 => [M1, A, M1, M2, Object, Kernel, BasicObject]

55.

`refine` `refine` `-W` 内での `include` が非推奨になった [Bug #17429] 内での `include / prepend` が非推奨になった を付けて実行すると警告が表示される `refine` 内での `incldue / prepend` は Ruby 3.2 で削除される予定 module Ex module Twice def twice self + self end end refine String do # warning: Refinement#include is deprecated and will be removed in Ruby 3.2 include Twice end end

56.

背景としては以下のように意図しない挙動が多発していたため using Module.new { module Twice def twice self + self end def double # Refinements twice これが を経由して呼び出せない end end refine String do include Twice end } # OK : Twice#double p "homu".twice 内から Twice#twice を呼び出せる 内から が呼び出せない # NG : Twice#double Twice#twice # error: `double': undefined local variable or method `twice' for 42:Integer (NameError) p "mami".double

57.

`import_methods` `include / prepend` 追加された 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 が追加された [Bug #17429] の変わりに `refine` 内でモジュールを組み込む機能として `import_methods` が

58.

を利用すると『継承リストにモジュールが追加される』のではなくて『モジュールのメ ソッドが直接 `Refinements` オブジェクト』に定義される `import_methods` class X; end module M1 def hoge; end refine X do include M1 end # X の継承リストに追加される end module M2 def foo; end refine X do # M2 Refinements import_methods M2 end end using M1; using M2 のメソッドが p X.instance_method(:hoge).owner p X.instance_method(:foo).owner オブジェクトに直接追加される # => M1 # => #<refinement:X@M2>

59.

ただし `import_methods` では Ruby のコード以外で定義されているモジュールは取り込めないので注意 など CRuby で定義されているモジュールは取り込めない C拡張で定義されているモジュールも取り込めない `Enumerable` module Ex refine String do # error: Can't import method which is not defined with Ruby code: Enumerable#drop (ArgumentError) import_methods Enumerable end end

60.

`load` にモジュールを渡せるようになった [Feature #6210] `Kernel#load` # test.rb class Foo def foo "foo" end end def hoge "hoge" end にモジュールを渡す事でそのモジュール内でコードが展開されるようになる module M; end に対して # M test.rb load "./test.rb", M の中身が定義される クラスが M のインナークラスになる # Foo p M::Foo # => M::Foo p M::Foo.new.foo # => "foo" class X # M#hoge include M public :hoge end が定義されている p X.new.hoge # => "hoge"

61.

にキーワード引数を渡すと警告がでるよ うになる [Feature #16806] 背景として がデフォルトでキーワード引数を受け取るようにする対応が進んでいる `Struct#initialize` `Struct#initialize` User = Struct.new(:name, :age) これは以前の挙動のまま # p User.new("homu", 14) # => #<struct User name="homu", age=14> キーワード引数を渡すと # keyword_init: true p User.new(name: "homu", age: 14) # => #<struct User name="homu", age=14> と同じようにキーワード引数で初期化される

62.
[beta]
にキーワード引数を渡すと警告がでるよ
うになる
[Feature
#16806]
背景として
がデフォルトでキーワード引数を受け取るようにする対応が進んでいる
`Struct#initialize`
`Struct#initialize`

User = Struct.new(:name, :age)

これは以前の挙動のまま

#
p User.new("homu", 14)
# => #<struct User name="homu", age=14>

キーワード引数を渡すと

#
keyword_init: true
p User.new(name: "homu", age: 14)
# => #<struct User name="homu", age=14>

と同じようにキーワード引数で初期化される

しかし、この変更により以下のコードが非互換になってしまう
User = Struct.new(:name, :age)

現状だと
現状
対応後

に

オブジェクトが入ってしまうので既存の挙動と変わってしまう

#
name
Hash
p User.new(name: "homu", age: 14)
#
=> #<struct User name={:name=>"homu", :age=>14}, age=nil>
#
=> #<struct User name="homu", age=14>

63.
[beta]
なので Ruby 3.1 では挙動は変更せずにキーワード引数を渡した場合に警告が出るようになっている
明示的に Hash オブジェクトを渡した場合は警告はでない

User = Struct.new(:name, :age)

警告は出るが挙動はそのまま

#
# warning: Passing only keyword arguments to Struct#initialize will behave differently from Ruby 3.2. Please use a
Hash literal like .new({k: v}) instead of .new(k: v).
p User.new(name: "homu", age: 14)
# => #<struct User name={:name=>"homu", :age=>14}, age=nil>

明示的に

#
Hash
# no warning

オブジェクトを渡した場合は警告はでない

p User.new({ name: "homu", age: 14 })
# => #<struct User name={:name=>"homu", :age=>14}, age=nil>

64.
[beta]
なので Ruby 3.1 では挙動は変更せずにキーワード引数を渡した場合に警告が出るようになっている
明示的に Hash オブジェクトを渡した場合は警告はでない

User = Struct.new(:name, :age)

警告は出るが挙動はそのまま

#
# warning: Passing only keyword arguments to Struct#initialize will behave differently from Ruby 3.2. Please use a
Hash literal like .new({k: v}) instead of .new(k: v).
p User.new(name: "homu", age: 14)
# => #<struct User name={:name=>"homu", :age=>14}, age=nil>

明示的に

#
Hash
# no warning

オブジェクトを渡した場合は警告はでない

p User.new({ name: "homu", age: 14 })
# => #<struct User name={:name=>"homu", :age=>14}, age=nil>

`keyword_init:`

を渡した場合は警告はでない

User = Struct.new(:name, :age, keyword_init: true)
# no warning
p User.new(name: "homu", age: 14)
# => #<struct User name="homu", age=14>

65.

`Enumerable#each_cons` `Enumerable#each_cons / each_slice` [1, 2, 3].each_cons(2){} # 3.0 => nil # 3.1 => [1, 2, 3] [1, 2, 3].each_slice(2){} # 3.0 => nil # 3.1 => [1, 2, 3] などの戻り値が変わった [GH-1509] の戻り値が `nil` からレシーバに変わった

66.

`Enumerable#each_cons` `Enumerable#each_cons / each_slice` などの戻り値が変わった [GH-1509] の戻り値が `nil` からレシーバに変わった [1, 2, 3].each_cons(2){} # 3.0 => nil # 3.1 => [1, 2, 3] [1, 2, 3].each_slice(2){} # 3.0 => nil # 3.1 => [1, 2, 3] これの影響で RuboCop が壊れた 修正コミット 以下のようなコードの実装で壊れていた def block_end_align_target(node) lineage = [node, *node.ancestors] target = lineage.each_cons(2) do |current, parent| break current if end_align_target?(current, parent) end target || lineage.last end

67.

`Enumerable#tally` `Enumerable#tally` が Hash を受け取る [Feature #17744] が結果を貯める Hash を受け取るようになった h = {} の結果が に挿入される # tally h [:a,:b,:c].tally(h) [:a,:b,:d].tally(h) p h #=> {:a=>2, :b=>2, :c=>1, :d=>1}

68.

その他 `MatchData#match` が追加 が追加 `TracePoint.allow_reentry` が追加 `instance_eval / exec` のパフォーマンスが改善された etc… `MatchData#match_length` https://github.com/ruby/ruby/blob/master/NEWS.md を見てね!

69.

まとめ

70.

まとめ

71.

まとめ Ruby 3.0 と比べると控えめと思いつつ結構いろんな機能が追加された 特に Hash の省略記法は前々からいろんな記法で山のように提案されていたのでついに来たか…って感じ

72.

まとめ Ruby 3.0 と比べると控えめと思いつつ結構いろんな機能が追加された 特に Hash の省略記法は前々からいろんな記法で山のように提案されていたのでついに来たか…って感じ あとは Refinements 周りも改善されていてよい Ruby 3.2 でも色々と機能追加されるので楽しみ

73.

まとめ Ruby 3.0 と比べると控えめと思いつつ結構いろんな機能が追加された 特に Hash の省略記法は前々からいろんな記法で山のように提案されていたのでついに来たか…って感じ あとは Refinements 周りも改善されていてよい Ruby 3.2 でも色々と機能追加されるので楽しみ 個人的には古いチケットがサルベージされている事が多かった印象 代入式の評価順や `load` の引数追加、 `#private` の戻り値、 `#private?` の追加などなど

74.

まとめ Ruby 3.0 と比べると控えめと思いつつ結構いろんな機能が追加された 特に Hash の省略記法は前々からいろんな記法で山のように提案されていたのでついに来たか…って感じ あとは Refinements 周りも改善されていてよい Ruby 3.2 でも色々と機能追加されるので楽しみ 個人的には古いチケットがサルベージされている事が多かった印象 代入式の評価順や `load` の引数追加、 `#private` の戻り値、 `#private?` の追加などなど 個人的に注目している機能は `load` にモジュールを渡せるようにする機能 なんか色々と面白いことができるんじゃないか期待している

75.

まとめ Ruby 3.0 と比べると控えめと思いつつ結構いろんな機能が追加された 特に Hash の省略記法は前々からいろんな記法で山のように提案されていたのでついに来たか…って感じ あとは Refinements 周りも改善されていてよい Ruby 3.2 でも色々と機能追加されるので楽しみ 個人的には古いチケットがサルベージされている事が多かった印象 代入式の評価順や `load` の引数追加、 `#private` の戻り値、 `#private?` の追加などなど 個人的に注目している機能は `load` にモジュールを渡せるようにする機能 なんか色々と面白いことができるんじゃないか期待している 無事に Ruby 3.1 がリリースされるのが楽しみ 今回紹介できなかった機能は他にもあるので詳しくは `NEWS` を見てね!