2021/11/25 今回の気になった bugs.ruby のチケット
今週は load
メソッドにモジュールを渡せるようになりました。
[Bug #17675] StringIO#each_byte doesn't check for readabilty while iterating
- IO がクローズしているのにイテレーションが処理されてしまうというバグ報告
require "stringio" strio = StringIO.new("1234") strio.each_byte do |byte| puts byte # ここでクローズしているがイテレーションは引き続き処理されている strio.close end # => 49 # 50 # 51 # 52
- このバグは修正済みで最新版では
IOError
が発生する- おそらくマイナーバージョンでバックポートされる
require "stringio" strio = StringIO.new("1234") strio.each_byte do |byte| puts byte strio.close end # => 49 # error: `each_byte': not opened for reading (IOError)
[Misc #18352] What is the Hash#grep expected?
Hash#grep
はなにを期待しているのか?という質問Array#grep
の場合は以下のように利用できる
[:foo1, :foo2, :bar].grep /foo/ # => [:foo1, :foo2]
Hash#grep
は以下のようになりなにを期待しているのかがよくわからない
{foo: '100', bar: '200'}.grep /foo/ # => []
#grep
は#===
メソッドで判定しているので以下のように利用できるとコメントされている
class HashMatcher < Struct.new(:key, :value, keyword_init: true) def ===((k, v)) (key.nil? || key === k) && (value.nil? || value === v) end end {foo1: '100', foo2: '200', bar: '200'}.grep(HashMatcher[key: /foo/]) # => [[:foo1, "100"], [:foo2, "200"]]
[Feature #18262] Enumerator::Lazy#partition
- 以下のような場合はファイル全部が読み込まれてしまう
file = File.open('very-large-file.txt') lines_with_errors, lines_without_errors = file.lazy.partition { _1.start_with?('E:') } lines_with_errors.class # => Array, all file is read by this moment
- これを改善するために
Enumerator::Lazy#partition
がEnumerator::Lazy
を返すようにする提案 - 以下のように使えるのを想定している
# Enumerator.produce で 1, 2, 3,... という無限Range を生成する Enumerator.produce(1) { |i| puts "processing #{i}"; i + 1 }.lazy .take(30) .partition(&:odd?) .then { |odd, even| # partition の戻り値から必要な数だけを取得する p odd.first(3), even.first(3) } # Prints: # processing 1 # processing 2 # processing 3 # processing 4 # processing 5 # [1, 3, 5] # [2, 4, 6]
- これは普通に便利そう
[Feature #12495] Make "private" return the arguments again, for chaining
private
の戻り値をレシーバから引数を返すようにする提案
class X def hoge; end p private :hoge # 現在の挙動 => X # 変更する挙動 => :hoge end
- 以下のようなことをやりたい
def cached(name) # Rewrite method to include a cache return name end # これは OK private cached def foo() end # こうもかけるようにしたい cached private def foo() end
- これはマージされて Ruby 3.1 から挙動が変わる
class X def hoge; end p private :hoge # Ruby 3.0 => X # Ruby 3.1 => :hoge end
[Feature #11256] anonymous block forwarding
def foo(a) yield a end def bar(&) # ブロック引数を foo にフォワードする foo(1, &) end bar { p _1 }
- また
&
を省略する事はできない
def foo(&) = bar(&) # OK def foo = bar(&) # NG
- またブロックからは使えないぽい?
def hoge; end # no anonymous block parameter proc { |&| hoge(&) }
[Feature #6210] load should provide a way to specify the top-level module
load
メソッドにModule
を指定できるようにする提案- 以下のように特定のモジュールに対して
load
した Ruby のコードが展開される
# test.rb def hoge "hoge" end class Foo def foo "foo" end end
module M end # M に対して test.rb の中身が定義される load "./test.rb", M p M::Foo # => M::Foo p M::Foo.new.foo # => "foo" class X include M public :hoge end p X.new.hoge # => "hoge"
- これがマージされて Ruby 3.1 からこの機能が使えるようになった
[Feature #18331] Kernel.#Time
Kernel.#Integer
などと同じようなKernel.#Time
を追加する提案Time.new
の短縮形としてほしいみたい
Time("2021-11-13T21:21:18.027294 +0900") # => 2021-11-13 21:21:18.027294 +0900 Time("2021-11-13 21:21:18.027294 +0900") # => 2021-11-13 21:21:18.027294 +0900 Time("foo", exception: false) # => nil