2022/02/10 今回の気になった bugs.ruby のチケット
今週はエンコーディングの ASCII_8BIT
という名前を BINARY
に変える提案がありました。
[Feature #18576] Rename ASCII-8BIT
encoding to BINARY
- エンコーディングの
ASCII-8BIT
をBINARY
という名前に変更する提案 - 以下のようなエラーメッセージで
ASCII-8BIT
と表示されても分かりづらいらしい
>> "fée" + "\xFF".b (irb):3:in `+': incompatible character encodings: UTF-8 and ASCII-8BIT (Encoding::CompatibilityError)
- 現状は
BINARY
がASCII_8BIT
のエイリアスとして存在しているんですがそれを逆にする感じなんですかね
pp Encoding::ASCII_8BIT # => #<Encoding:ASCII-8BIT> pp Encoding::BINARY # => #<Encoding:ASCII-8BIT>
[Bug #18575] [BUG] unsupported: T_NONE
- 巨大な CSV ファイルを処理している時にクラッシュするというバグ報告
- 以下のコードで再現するらしい
require 'csv' parsed = CSV.parse("Foo,bAr,baZ\nfoo,bar,baz", headers: true) while true parsed.map do |row| obj = row.to_h obj.transform_keys! { |k| k.strip.downcase } end end
- 手元だと Ruby 3.0.2 で再現したけど 3.0.3 では動いていたので直ってるかも?
- CSV のバージョンに依存しているのかも?
- https://bugs.ruby-lang.org/issues/18575#note-3
[Feature #18573] Object#pack1
Array#pack
を使用する時に配列の要素が1つのケースがよくある- 標準ライブラリなどでもあるらしい
[codepoint].pack('U') [digest].pack('m0') [mail_body].pack('M') [ip_address].pack('N')
- このような際にわざわざ
Array
にするのが手間なのでObject#pack1
というメソッドを追加する提案
codepoint.pack('U') digest.pack('m0') mail_body.pack('M') ip_address.pack('N')
Object
に生やすのではなくてString.pack1(format, arg)
を追加するのはどうか、みたいなコメントとかもあります- ちなみに
Array#pack
は指定されたテンプレートに沿って文字列に変換するメソッド
# コードポイントから UTF-8 の文字列に変換する pp [12354].pack("U*") # => "あ"
[Bug #18572] Performance regression when invoking refined methods
- Ruby 2.7 と比較して
Refinement
で定義したメソッドの呼び出しが遅くなっているというバグ報告using
していなくても遅くなっている
- 以下、検証結果
require "benchmark_driver" source = <<~RUBY class Foo def original end def refined end end module FooRefinements refine Foo do def refined raise "never called" end end end FOO = Foo.new RUBY Benchmark.driver do |x| x.prelude %Q{ #{source} } x.report "no-op original", %{ FOO.original } x.report "no-op refined", %{ FOO.refined } end
- Ruby 3.2.0-dev
... Comparison: no-op original: 54831732.8 i/s no-op refined: 28231384.4 i/s - 1.94x slower
- Ruby 2.7.5
... Comparison: no-op refined: 57847396.8 i/s no-op original: 56289619.5 i/s - 1.03x slower
[Bug #18569] RubyVM::InstructionSequence#disasm returns nil for composed functions
Proc#>>
の結果をRubyVM::InstructionSequence#disasm
に渡すとnil
が返ってくるというバグ報告
# Proc オブジェクト渡すとそのブロックの命令が返ってくる first_proc = proc { |x| x + 2 } puts RubyVM::InstructionSequence.disasm(first_proc) # => # == disasm: #<ISeq:block in <main>@disasm.rb:3 (3,18)-(3,31)> (catch: FALSE) # local table (size: 1, argc: 1 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1]) # [ 1] x@0<Arg> # 0000 getlocal_WC_0 x@0 ( 3)[LiBc] # 0002 putobject 2 # 0004 opt_plus <calldata!mid:+, argc:1, ARGS_SIMPLE>[CcCr] # 0006 leave [Br] # ------------------------------------- # Proc#>> の結果を .disasm に渡すと nil が返ってくる pp RubyVM::InstructionSequence.disasm(first_proc >> first_proc) # => nil
- これは
Proc#>>
の結果が命令シーケンスを持っていないからが理由とのこと - 命令シーケンスが必要な場合は自分で
Proc
オブジェクトを生成する必要がある
first_proc = proc { |x| x + 2 } # これだと OK puts RubyVM::InstructionSequence.disasm(proc { |x| first_proc.call(x) + 2 }) # => # == disasm: #<ISeq:block in <main>@disasm.rb:3 (3,18)-(3,31)> (catch: FALSE) # local table (size: 1, argc: 1 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1]) # [ 1] x@0<Arg> # 0000 getlocal_WC_1 first_proc@0 ( 2)[LiBc] # 0002 getlocal_WC_0 x@0 # 0004 opt_send_without_block <calldata!mid:call, argc:1, ARGS_SIMPLE> # 0006 putobject 2 # 0008 opt_plus <calldata!mid:+, argc:1, ARGS_SIMPLE>[CcCr] # 0010 leave [Br]
[Bug #18578] Hash#shift を繰り返していると ruby が無応答になる。
- 以下のように
Hash#shift
を繰り返し呼び出すと Ruby の実行が止まってしまうことがるというバグ報告
H = {} 100.times{|n| while H.size < n k = Random.rand 0..1<<30 H[k] = 1 # たぶんここで止まる。 end warn "size: #{H.size} before shifting." 0 while H.shift warn "empty?: #{H.empty?}" } warn :exit
- このバグは Ruby 2.5 から発生している
Hash
が空になった後にHash#shift
を呼び出すと意図しない挙動になっていたぽい0 while H.shift
の変わりにH.shift until H.empty?
を使うと問題なく動作する- https://bugs.ruby-lang.org/issues/18578#note-3
- このバグは既に修正済み