Skip to content

IO: timeout / timeout= / wait_priority と IO::TimeoutError を追加 (Ruby 3.2)#3311

Open
Watson1978 wants to merge 2 commits into
rurema:masterfrom
Watson1978:io-timeout-and-wait-priority
Open

IO: timeout / timeout= / wait_priority と IO::TimeoutError を追加 (Ruby 3.2)#3311
Watson1978 wants to merge 2 commits into
rurema:masterfrom
Watson1978:io-timeout-and-wait-priority

Conversation

@Watson1978

Copy link
Copy Markdown
Contributor

概要

Ruby 4.0 に存在するのにリファレンスに項目が無い [c:IO] の入出力タイムアウト関連の
API を追加しました。いずれも Ruby 3.2 で追加されたものです。

  • IO#timeout — 設定されている入出力タイムアウトの取得
  • IO#timeout= — 入出力タイムアウトの設定
  • IO#wait_priority — 優先データの読み込み待ち
  • IO::TimeoutError — タイムアウト時に発生する例外 (< IOError)

getter も未収録でした

未収録 API の洗い出しでは IO#timeout= だけが挙がっていましたが、
getter の IO#timeout も未収録でした。timeout ライブラリの
[m:Kernel#timeout] と名前が衝突して収録済みと誤検出されていたためです。
getter/setter の対として両方追加しています。

IO::TimeoutError は独立ファイルにしました

[c:IO] の本体ファイル (IO.md) は front matter に include(Enumerable,
File::Constants) を持つため、同じファイルに例外クラスを同居させると
multiple entities in a file with front matter relations でビルドに失敗します。
IO::Buffer 系の例外と同じく IO__TimeoutError.md として独立ファイルにし、
版の出し分けは front matter の since: "3.2" で行いました。

登場バージョン

2.7.8 〜 3.1.6: なし
3.2.11 以降:    timeout, timeout=, wait_priority, IO::TimeoutError

記述の根拠

  • IO#timeout の既定値は nil で、設定すると値を返します。タイムアウトを設定した
    IO に対する読み込みで [c:IO::TimeoutError] が発生することを実機で確認しました。
$ ruby -e 'r, w = IO.pipe; r.timeout = 0.1; r.read'
-e:1:in 'IO#read': Timed out! (IO::TimeoutError)
  • wait_priority は引数 timeout を取り、読み込み可能で真、タイムアウト時に nil を
    返すことを実機で確認しました。

検証

  • rake check_blank_lines / check_indent_in_samplecode / check_single_space_indent
  • bitclust update --markdowntree=manual/api を 3.1 / 3.2 / 3.3 / 4.0 で実行し、
    エラーが出ないこと、登録される項目が 0 / 4 / 4 / 4 件と 3.2 追加どおりに
    なること、および IO#wait_readable などの参照リンクが解決することを確認しました。

🤖 Generated with Claude Code

いずれも Ruby 3.2 で追加されたもの。実機で確認し版分岐した。

  IO#timeout          設定されている入出力タイムアウトの取得
  IO#timeout=         入出力タイムアウトの設定
  IO#wait_priority    優先データの読み込み待ち
  IO::TimeoutError    タイムアウト時に発生する例外 (< IOError)

トラッカーでは IO#timeout= だけが未収録扱いだったが、getter の IO#timeout も
未収録だった (timeout ライブラリの Kernel#timeout と名前が衝突して収録済みと
誤検出されていた)。getter/setter の対として両方追加した。

IO::TimeoutError は IO.md が front matter に include を持つため同居できない
(multiple entities in a file with front matter relations になる)。
IO__Buffer 系の例外と同じく IO__TimeoutError.md として独立ファイルにし、
版の出し分けは front matter の since: "3.2" で行った。

IO#timeout の既定値が nil、設定すると値を返すこと、タイムアウト時に
IO::TimeoutError が発生することを実機で確認した。wait_priority の引数と
返り値 (真、またはタイムアウト時 nil) も実機と rdoc で確認済み。

bitclust のデータベース生成を 3.1 / 3.2 / 3.3 / 4.0 で実行してエラーが出ないこと、
登録される項目が 0 / 4 / 4 / 4 件と 3.2 追加どおりになること、および
IO#wait_readable などの参照リンクが解決することを確認済み。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@znz

znz commented Jul 25, 2026

Copy link
Copy Markdown
Member

レビューありがとうございます。実機(all-ruby, Ruby 3.1.6〜4.0.6)で確認しました。

IO#timeout / IO#timeout= / IO::TimeoutError は問題ありません。

  • 3 つとも 3.2 以降で追加(3.1 では IO#timeout が NoMethodError)で、#@since 3.2 および front matter since: "3.2" は正しいです。
  • timeout= に数値を設定 → timeout で取得、nil で解除、を確認しました。
  • タイムアウトを超えた readIO::TimeoutError が発生することを確認しました(3.2+)。
  • IO::TimeoutError の継承は IO::TimeoutError < IOError < StandardError で、# class IO::TimeoutError < IOError は正しいです。

1 点、IO#wait_priority配置について相談させてください。

wait_priorityio/wait.md の方が自然では

wait_priority の兄弟である wait_readable / wait_writable / wait は、現状 manual/api/io/wait.md(io/wait ライブラリのドキュメント)で定義されています。実機で確認したところ、これら 4 つは いずれも Ruby 3.2 で require 'io/wait' なしに使えるようになりました(3.1 では 4 つとも require が必要)。

つまり wait_priority だけを _builtin/IO.md に置くと、

  1. 兄弟メソッドと定義場所が分かれてしまう
  2. #@since 3.2 を付けることで since バッジが「3.2 から」になりますが、io/wait.md 側の兄弟(版で囲まれていない)はそのバッジを持たず、表示が揃いません。wait_priority 自体は io/wait 経由では 3.2 以前から存在します。

兄弟と揃えて manual/api/io/wait.md# reopen IO 配下)に置く方が一貫すると思いますが、いかがでしょうか。timeout / timeout= / IO::TimeoutError は core 由来なので _builtin/IO.md のままで問題ありません。

(任意)wait_priority の返り値の説明は「真を返す/nil を返す」となっていますが、シグネチャは bool | self | nil です。wait_readable の説明のように「一度ブロックしてから可能になった場合は self、内部バッファにある場合は true」に触れると、self のケースの説明が揃います。

🤖 Generated with Claude Code

wait / wait_readable / wait_writable と定義場所を揃える。実機で確認したところ
この 4 つは 3.0 / 3.1 では require "io/wait" が必要で、3.2 以降は require なしで
使える。wait_priority だけ _builtin/IO.md に #@SInCE 3.2 で置くと、兄弟と
定義場所が分かれ、since バッジも揃わない。

ただし io/wait.md は版で囲まれていないため、そのままだと 1.8.7〜2.7.0 の
ページにも出てしまう。require "io/wait" しても 2.7.8 では wait_priority が
未定義で 3.0.7 から存在するので、このエントリだけ #@SInCE 3.0 で囲んだ。

返り値の説明も wait_readable と同じ 3 ケース (バッファにあれば true、
ブロック後に可能になれば self、タイムアウトで nil) に揃えた。
io_wait_priority が rb_io_read_pending なら Qtrue、そうでなければ
io_wait_event(io, RUBY_IO_PRIORITY, timeout, 1) を返す実装と一致する。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@Watson1978

Copy link
Copy Markdown
Contributor Author

レビューありがとうございます。ご相談の点、おっしゃるとおりだと思うので移動しました。

wait_priorityio/wait.md へ移しました

_builtin/IO.md#@since 3.2 ブロックから削除し、manual/api/io/wait.md
# reopen IO 配下、wait_writable の直後に置きました。

前提のご指摘も実機で一致しました。wait / wait_readable / wait_writable /
wait_priority の 4 つは 3.0 / 3.1 では require が必要で、3.2 以降は require なしで
使えます(nread / ready? は 3.2 以降も require が必要)。

3.0.7  require前: wait=false wait_readable=false wait_writable=false wait_priority=false
       require後: すべて true
3.1.6  同上
3.2.11 require前: wait=true wait_readable=true wait_writable=true wait_priority=true

1 点、#@since 3.0 を付けています

io/wait.md は版で囲まれていないので、そのまま置くと 1.8.7 〜 2.7.0 のページにも
出力されてしまいます。実機で確認したところ wait_priorityrequire "io/wait"
しても 2.7.8 では未定義で、3.0.7 から存在します。

2.7.8  require "io/wait" 後: IO.method_defined?(:wait_priority) # => false
3.0.7  require "io/wait" 後: IO.method_defined?(:wait_priority) # => true

そのため、このエントリだけ #@since 3.0 で囲みました。兄弟の 3 つは 2.x にも
あるので囲んでいません。

(任意) 返り値の説明

ご提案どおり、wait_readable と同じ 3 ケースの形に揃えました。

  • 一度ブロックしてから読み込み可能になった場合は self
  • 内部のバッファにデータがある場合はブロックせずに true
  • タイムアウトした場合は nil

io_wait_priority の実装とも一致しています(rb_io_read_pending なら Qtrue
そうでなければ io_wait_event(io, RUBY_IO_PRIORITY, timeout, 1)selfnil)。

検証

版ごとに DB を生成して確認しました。

bitclust lookup --method='IO#wait_priority'
2.7.0 no such method
3.0 / 3.2 / 4.0 library: io/wait で登録

io/wait.md_builtin/IO.md 由来の全エントリについて [m:...] / [c:...]
DB と突き合わせ、2.7.0 / 3.0 / 3.2 / 4.0 のいずれも NG 0 件でした。

参考(本 PR 対象外): nread / ready? が 4.0 で無くなっています

確認の過程で気づいた別件です。io/wait.mdnreadready? を版で囲まずに
載せていますが、4.0.6 では require "io/wait" してもどちらも未定義でした
(3.4.10 までは require で定義されます)。

3.4.10 require後: nread=true  ready?=true
4.0.6  require後: nread=false ready?=false

#@until 4.0 が要るかもしれません。本 PR の範囲外なので手は付けていません。

🤖 Generated with Claude Code

@znz

znz commented Jul 25, 2026

Copy link
Copy Markdown
Member

wait_priority の移動ありがとうございます。確認しました。

  • _builtin/IO.md から wait_priority が完全に除去され(grep で該当 0)、#@since / #@end の対応が崩れていない(depth 0)ことを確認しました。
  • manual/api/io/wait.mdwait_writable の後に 1 回だけ追加され、同ファイルの他の wait_* メソッドと揃えて #@since 3.0 でゲートされている点も確認しました(wait / wait_readable / wait_writable / wait_priority は 3.0/3.1 では require "io/wait" 必要・3.2 から組み込み、という Watson さんの調査とも整合します)。

3.0 / 3.2 / 4.0 で statichtml をビルドし、いずれも compileerror 0、wait_priority ページが 3.0 以降で生成され、SEE(wait_readable / wait_writable)が解決すること、IO#timeout / IO#timeout= / IO::TimeoutError が 3.2 から出ることを確認しました。マージ可と考えます。 ありがとうございました。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants