---
title: Ruby 3.1 に備えよう！
tags: 
author: [osyo](https://convert.docswell.com/user/pink_bangbi)
site: [Docswell](https://www.docswell.com/)
thumbnail: https://bcdn.docswell.com/page/V9E29ZKD7R.jpg?width=480
description: Ruby 3.1 に備えよう！ by osyo
published: December 17, 21
canonical: https://convert.docswell.com/s/pink_bangbi/KXWG2Z-2021-12-17-185213
---
# Page. 1

![Page Image](https://bcdn.docswell.com/page/V9E29ZKD7R.jpg)

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


# Page. 2

![Page Image](https://bcdn.docswell.com/page/5D7Y4RNMEM.jpg)

自己紹介
名前：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


# Page. 3

![Page Image](https://bcdn.docswell.com/page/2VENYDX3J8.jpg)

Ruby 3.1 に備えよう！


# Page. 4

![Page Image](https://bcdn.docswell.com/page/GY79PG8PE3.jpg)

！！！注意！！！


# Page. 5

![Page Image](https://bcdn.docswell.com/page/5G78DV8X7D.jpg)

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


# Page. 6

![Page Image](https://bcdn.docswell.com/page/ML7LM5RNJR.jpg)

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


# Page. 7

![Page Image](https://bcdn.docswell.com/page/54EMY3RQEW.jpg)

静的解析


# Page. 8

![Page Image](https://bcdn.docswell.com/page/ZPER9QRKJ9.jpg)

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


# Page. 9

![Page Image](https://bcdn.docswell.com/page/NP7XQ5R5EX.jpg)

デバッガが追加
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


# Page. 10

![Page Image](https://bcdn.docswell.com/page/637K96RR7D.jpg)

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


# Page. 11

![Page Image](https://bcdn.docswell.com/page/4LJ3W68GJ5.jpg)

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


# Page. 12

![Page Image](https://bcdn.docswell.com/page/V8JDKVMNEG.jpg)

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


# Page. 13

![Page Image](https://bcdn.docswell.com/page/4VEPKVRN78.jpg)

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


# Page. 14

![Page Image](https://bcdn.docswell.com/page/L27VVZRY7Q.jpg)

言語機能


# Page. 15

![Page Image](https://bcdn.docswell.com/page/Z5JGL4MW7L.jpg)

Hash
の省略記法
[Feature
#14579]
Hash を定義する時に値を省略するとキーと同じ名前の変数やメソッドを参照する
や `foo(x:, y:)` が `{ x: x, y: y }` や `foo(x: x, y: y)` となる
同名の変数、メソッド、定数が参照される
`{ x:, y: }`
def name
&quot;homu&quot;
end
age = 42
# { id: 1, name: name, age: age }
と同じ意味
homu = { id: 1, name:, age: }
pp homu
# =&gt; {:id=&gt;1, :name=&gt;&quot;homu&quot;, :age=&gt;42}
リテラルだけではなくてメソッドのキーワード引数でも同様
と同じ意味
# Hash
# pp(name: name, age: age)
pp(name:, age:)
# =&gt; {:name=&gt;&quot;homu&quot;, :age=&gt;42}
参照：Ruby 3.1 で { a: a } が { a: } とかけるようになるらしい - Secret Garden(Instrumental)}


# Page. 16

![Page Image](https://bcdn.docswell.com/page/V47QYGRQEP.jpg)

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


# Page. 17

![Page Image](https://bcdn.docswell.com/page/DKE4W58YJ1.jpg)

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


# Page. 18

![Page Image](https://bcdn.docswell.com/page/PL71YW2NJG.jpg)

パターンマッチの `^` が式に対応 [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
が
内であればここが呼ばれる


# Page. 19

![Page Image](https://bcdn.docswell.com/page/8G7WG62ME2.jpg)

パターンマッチの `^` が式に対応 [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
#=&gt; [[3, 5], [5, 7], [11, 13]]


# Page. 20

![Page Image](https://bcdn.docswell.com/page/W4JZLYDME3.jpg)

パターンマッチの `^` が @変数などに対応 [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 内であればここが呼ばれる


# Page. 21

![Page Image](https://bcdn.docswell.com/page/KYE6WD15EV.jpg)

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


# Page. 22

![Page Image](https://bcdn.docswell.com/page/5GE5M34GE4.jpg)

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


# Page. 23

![Page Image](https://bcdn.docswell.com/page/V9729ZVDJR.jpg)

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


# Page. 24

![Page Image](https://bcdn.docswell.com/page/5DJY4R3M7M.jpg)

1行パターンマッチが
Experimental
でなくなった
Ruby 3.0 から実験的に実装されていた1行パターンマッチが Ruby 3.1 から実験的でなくなった
user = { name: &quot;homu&quot;, 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 =&gt; { name:, age: }
p name # = &quot;homu&quot;
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 &quot;OK&quot;
end


# Page. 25

![Page Image](https://bcdn.docswell.com/page/2V7NYDV3E8.jpg)

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


# Page. 26

![Page Image](https://bcdn.docswell.com/page/GYJ9PG6P73.jpg)

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


# Page. 27

![Page Image](https://bcdn.docswell.com/page/5GJ8DVZXJD.jpg)

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


# Page. 28

![Page Image](https://bcdn.docswell.com/page/MLJLM5DNER.jpg)

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


# Page. 29

![Page Image](https://bcdn.docswell.com/page/547MY3PQ7W.jpg)

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


# Page. 30

![Page Image](https://bcdn.docswell.com/page/ZP7R9Q1KE9.jpg)

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


# Page. 31

![Page Image](https://bcdn.docswell.com/page/NPJXQ5Y57X.jpg)

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


# Page. 32

![Page Image](https://bcdn.docswell.com/page/63JK963RJD.jpg)

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


# Page. 33

![Page Image](https://bcdn.docswell.com/page/4LE3W6GGE5.jpg)

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


# Page. 34

![Page Image](https://bcdn.docswell.com/page/V8EDKV1N7G.jpg)

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


# Page. 35

![Page Image](https://bcdn.docswell.com/page/4V7PKVQNJ8.jpg)

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


# Page. 36

![Page Image](https://bcdn.docswell.com/page/L2JVVZ5YJQ.jpg)

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


# Page. 37

![Page Image](https://bcdn.docswell.com/page/Z5EGL46WJL.jpg)

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


# Page. 38

![Page Image](https://bcdn.docswell.com/page/V4JQYG4Q7P.jpg)

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


# Page. 39

![Page Image](https://bcdn.docswell.com/page/DK74W5QYE1.jpg)

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=` ）


# Page. 40

![Page Image](https://bcdn.docswell.com/page/PLJ1YWPNEG.jpg)

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 の場合


# Page. 41

![Page Image](https://bcdn.docswell.com/page/8GJWG6VM72.jpg)

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` が評価される


# Page. 42

![Page Image](https://bcdn.docswell.com/page/W4EZLY4M73.jpg)

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` が評価される


# Page. 43

![Page Image](https://bcdn.docswell.com/page/KY76WD357V.jpg)

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` が評価される


# Page. 44

![Page Image](https://bcdn.docswell.com/page/5G75M3LG74.jpg)

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` が評価される


# Page. 45

![Page Image](https://bcdn.docswell.com/page/V9J29ZLDER.jpg)

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]=` )


# Page. 46

![Page Image](https://bcdn.docswell.com/page/5DEY4RQMJM.jpg)

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=` ）


# Page. 47

![Page Image](https://bcdn.docswell.com/page/2VJNYDK378.jpg)

コアクラスの更新


# Page. 48

![Page Image](https://bcdn.docswell.com/page/GYE9PGVPJ3.jpg)

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


# Page. 49

![Page Image](https://bcdn.docswell.com/page/5GE8DVPXED.jpg)

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


# Page. 50

![Page Image](https://bcdn.docswell.com/page/MLELM51N7R.jpg)

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


# Page. 51

![Page Image](https://bcdn.docswell.com/page/54JMY3WQJW.jpg)

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


# Page. 52

![Page Image](https://bcdn.docswell.com/page/ZPJR9QYK79.jpg)

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


# Page. 53

![Page Image](https://bcdn.docswell.com/page/NPEXQ5G5JX.jpg)

`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 =&gt; [M1, A, M2, Object, Kernel, BasicObject]
3.0 =&gt; [A, M1, M2, Object, Kernel, BasicObject]


# Page. 54

![Page Image](https://bcdn.docswell.com/page/63EK964RED.jpg)

これの対処として 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 =&gt; [M1, A, M2, Object, Kernel, BasicObject]
# 3.0 =&gt; [A, M1, M2, Object, Kernel, BasicObject]
# 3.1 =&gt; [M1, A, M1, M2, Object, Kernel, BasicObject]


# Page. 55

![Page Image](https://bcdn.docswell.com/page/4L73W6LG75.jpg)

`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


# Page. 56

![Page Image](https://bcdn.docswell.com/page/V87DKVNNJG.jpg)

背景としては以下のように意図しない挙動が多発していたため
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 &quot;homu&quot;.twice
内から Twice#twice を呼び出せる
内から
が呼び出せない
# NG : Twice#double
Twice#twice
# error: `double&#039;: undefined local variable or method `twice&#039; for 42:Integer (NameError)
p &quot;mami&quot;.double


# Page. 57

![Page Image](https://bcdn.docswell.com/page/4VJPKV5NE8.jpg)

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


# Page. 58

![Page Image](https://bcdn.docswell.com/page/L2EVVZPYEQ.jpg)

を利用すると『継承リストにモジュールが追加される』のではなくて『モジュールのメ
ソッドが直接 `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
オブジェクトに直接追加される
# =&gt; M1
# =&gt; #&lt;refinement:X@M2&gt;


# Page. 59

![Page Image](https://bcdn.docswell.com/page/Z57GL4PWEL.jpg)

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


# Page. 60

![Page Image](https://bcdn.docswell.com/page/V4EQYG2QJP.jpg)

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


# Page. 61

![Page Image](https://bcdn.docswell.com/page/DKJ4W5LY71.jpg)

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


# Page. 62

![Page Image](https://bcdn.docswell.com/page/PLE1YWLN7G.jpg)

にキーワード引数を渡すと警告がでるよ
うになる
[Feature
#16806]
背景として
がデフォルトでキーワード引数を受け取るようにする対応が進んでいる
`Struct#initialize`
`Struct#initialize`
User = Struct.new(:name, :age)
これは以前の挙動のまま
#
p User.new(&quot;homu&quot;, 14)
# =&gt; #&lt;struct User name=&quot;homu&quot;, age=14&gt;
キーワード引数を渡すと
#
keyword_init: true
p User.new(name: &quot;homu&quot;, age: 14)
# =&gt; #&lt;struct User name=&quot;homu&quot;, age=14&gt;
と同じようにキーワード引数で初期化される
しかし、この変更により以下のコードが非互換になってしまう
User = Struct.new(:name, :age)
現状だと
現状
対応後
に
オブジェクトが入ってしまうので既存の挙動と変わってしまう
#
name
Hash
p User.new(name: &quot;homu&quot;, age: 14)
#
=&gt; #&lt;struct User name={:name=&gt;&quot;homu&quot;, :age=&gt;14}, age=nil&gt;
#
=&gt; #&lt;struct User name=&quot;homu&quot;, age=14&gt;


# Page. 63

![Page Image](https://bcdn.docswell.com/page/8GEWG6QMJ2.jpg)

なので 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: &quot;homu&quot;, age: 14)
# =&gt; #&lt;struct User name={:name=&gt;&quot;homu&quot;, :age=&gt;14}, age=nil&gt;
明示的に
#
Hash
# no warning
オブジェクトを渡した場合は警告はでない
p User.new({ name: &quot;homu&quot;, age: 14 })
# =&gt; #&lt;struct User name={:name=&gt;&quot;homu&quot;, :age=&gt;14}, age=nil&gt;


# Page. 64

![Page Image](https://bcdn.docswell.com/page/W47ZLYWMJ3.jpg)

なので 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: &quot;homu&quot;, age: 14)
# =&gt; #&lt;struct User name={:name=&gt;&quot;homu&quot;, :age=&gt;14}, age=nil&gt;
明示的に
#
Hash
# no warning
オブジェクトを渡した場合は警告はでない
p User.new({ name: &quot;homu&quot;, age: 14 })
# =&gt; #&lt;struct User name={:name=&gt;&quot;homu&quot;, :age=&gt;14}, age=nil&gt;
`keyword_init:`
を渡した場合は警告はでない
User = Struct.new(:name, :age, keyword_init: true)
# no warning
p User.new(name: &quot;homu&quot;, age: 14)
# =&gt; #&lt;struct User name=&quot;homu&quot;, age=14&gt;


# Page. 65

![Page Image](https://bcdn.docswell.com/page/KYJ6WDG5JV.jpg)

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


# Page. 66

![Page Image](https://bcdn.docswell.com/page/5GJ5M3VGJ4.jpg)

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


# Page. 67

![Page Image](https://bcdn.docswell.com/page/4LE3W6DPE5.jpg)

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


# Page. 68

![Page Image](https://bcdn.docswell.com/page/V8EDKVP37G.jpg)

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


# Page. 69

![Page Image](https://bcdn.docswell.com/page/4V7PKVNPJ8.jpg)

まとめ


# Page. 70

![Page Image](https://bcdn.docswell.com/page/L2JVVZKVJQ.jpg)

まとめ


# Page. 71

![Page Image](https://bcdn.docswell.com/page/Z5EGL4Q1JL.jpg)

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


# Page. 72

![Page Image](https://bcdn.docswell.com/page/V4JQYGKN7P.jpg)

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


# Page. 73

![Page Image](https://bcdn.docswell.com/page/DK74W5P3E1.jpg)

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


# Page. 74

![Page Image](https://bcdn.docswell.com/page/PLJ1YW9ZEG.jpg)

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


# Page. 75

![Page Image](https://bcdn.docswell.com/page/8GJWG6Q672.jpg)

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


