2021/06/17 今週の気になった bugs.ruby のチケット

今週は ENV に対して変更が入りました。

[Bug #17098] Float#negative? reports negative zero as not negative

  • -0.0Float#negative?false を返すのは期待しているのか?というバグ報告
    • IEEE 754 の規格?でそう定まってるらしい?
neg_zero = -0.0
pp neg_zero.negative?
# => false
pp neg_zero < 0
# => false
  • チケットを立てた人が期待する動作としてはこう
-0.0.negative?
# => true

0.0.positive?
# => false
  • その他、現状の挙動
pp RUBY_VERSION  # => "3.0.1"


# これは両方共 true
pp 0.0 == 0.0    # => true
pp -0.0 == -0.0  # => true

# equal? の場合
pp 0.0.equal?(0.0)    # => true
pp -0.0.equal?(-0.0)  # => false

# 変数に代入してから比較すると
a = -0.0
pp a.equal?(a)  # => true

puts "---"
# -0.0 か判定する方法
# https://bugs.ruby-lang.org/issues/17098#note-7
def check_negative_zero(f)
  1.0 / f == -Float::INFINITY
end
pp check_negative_zero(-0.0)
# => true
pp check_negative_zero(0.0)
# => false

[Feature #17950] Unable to pattern-match against a String key

  • パターンマッチでキーが String の場合にエラーになるというバグ報告
# Hash のキーに文字列がある場合、マッチする事ができない
case { status: 200, headers: {"content-type" => "application/json"}, body: "bla" }
in { status: , headers: { "content-type" => type }, body: }
end
# syntax error, unexpected terminator, expecting literal content or tSTRING_DBEG or tSTRING_DVAR or tLABEL_END
# ...tus: , headers: {"content-type" => type}, body: }
case { status: 200, headers: {"content-type" => "application/json"}, body: "bla" }
in { status: , headers: headers, body: } if type = headers["content-type"]
  pp type
  # => "application/json"
end
  • 早くパターンマッチ使いたい

[Bug #17767] Cloned ENV inconsistently returns ENV or self

  • ENVENV.clone したオブジェクトで挙動に一貫性がないというバグ報告
cloned_env = ENV.clone

p ENV.each_key{}.equal?(ENV) #=> true
p cloned_env.each_key{}.equal?(cloned_env) #=> true

ENV.delete('TEST')

err = ENV.fetch('TEST') rescue $!
p err.receiver.equal?(ENV) #=> true
err = cloned_env.fetch('TEST') rescue $!
p err.receiver.equal?(cloned_env) #=> false

ENV['TEST'] = 'TRUE'
p ENV.select!{ false }.equal?(ENV) #=> true

cloned_env['TEST'] = 'TRUE'
p cloned_env.select!{ false }.equal?(cloned_env) #=> false

[Bug #17951] Collisions in Proc#hash values for blocks defined at the same line

  • Proc#hash の値が同じ値になるケースがあるというバグ報告
require 'set'

def capture(&block)
  block
end

# 同じブロックを大量に生成する
blocks = Array.new(1000) { capture { :foo } }

hashes = blocks.map(&:hash).uniq
ids = blocks.map(&:object_id).uniq
equality = blocks.map { blocks[0].eql?(_1) }.tally
hash = blocks.to_h { [_1, nil] }
set = blocks.to_set

# hash が一意であれば hashes.size == 1000 になるはずだがなっていない
puts(hashes.size)      # => 11
puts(ids.size)         # => 1000
puts(equality.inspect) # => {true=>1, false=>999}
puts(hash.size)        # => 1000
puts(set.size)         # => 1000

[Bug #15993] 'require' doesn't work if there are Cyrillic chars in the path to Ruby dir

D:\users\киї\Ruby\2.6\bin>ruby -v
ruby 2.6.3p62 (2019-04-16 revision 67580) [x64-mingw32]

D:\users\киї\Ruby\2.6\bin>ruby -e "require 'logger'"
Traceback (most recent call last):
        1: from <internal:gem_prelude>:2:in `<internal:gem_prelude>'
<internal:gem_prelude>:2:in `require': No such file or directory -- D:/users/РєРёС—/Ruby/2.6/lib/ruby/2.6.0/rubygems.rb (LoadError)
  • チケットでは Ruby 2.6.3 で再現すると書かれている
    • これ自体 2年前のチケット
  • Ruby 2.7 以降では既に直っているので Close されている
D:\Евгений>C:\Ruby26-x64\bin\ruby -I D:\Евгений -e "require 'logger'"
Traceback (most recent call last):
        2: from -e:1:in `<main>'
        1: from C:/Ruby26-x64/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require'
C:/Ruby26-x64/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require': No such file or directory -- D:/Евгений/logger.rb (LoadError)

D:\Евгений>C:\Ruby27-x64\bin\ruby -I D:\Евгений -e "require 'logger'"

D:\Евгений>C:\Ruby30-x64\bin\ruby -I D:\Евгений -e "require 'logger'"
  • どうやって直ったのかが気になる…