2021/11/18 今回の気になった bugs.ruby のチケット
今週は Refinements 関連の便利メソッドのチケットが多いです。
[Bug #17429] Prohibit include/prepend in refinement modules
- Refinements 時に
include/prepend
することを禁止するチケット - 背景として以下の様に Refinements 時に
include/prepend
すると意図しない挙動がある
class X; end module M def foo hoge end def hoge "hoge" end refine X do include M end end using M # error `foo': undefined local variable or method `hoge' for #<X:0x000056087d251648> (NameError) # hoge は Refinements 内から呼ぶことができない # なぜなら foo メソッド内では using してないから… p X.new.foo
- これらを解決する仕組みとして新しく
Refinement#import_methods
というメソッドが導入された
class X; end module M def foo hoge end def hoge "hoge" end refine X do import_methods M end end using M p X.new.foo
Refinement#import_methods
を利用すると継承リストにモジュールが追加されるのではなくてモジュールのメソッドが直接Refinements
オブジェクトに定義される
class X; end module M1 def hoge; end refine X do # X の継承リストに追加される include M1 end 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 # => M1 p X.instance_method(:foo).owner # => #<refinement:X@M2>
- また
Refinement#include/prepend
は Ruby 3.2 で削除される予定なので-W
を付けて実行すると警告がでる
module M1 refine Object do # warning: Refinement#include is deprecated and will be removed in Ruby 3.2 include M1 # warning: Refinement#prepend is deprecated and will be removed in Ruby 3.2 prepend M1 end end
- これ自体はかなりよさそうなんですが互換性を保つようにするのがちょっと大変そう
- Refinements がよくなってうれいし
[Feature #18270] Refinement#{extend_object,append_features,prepend_features} should be removed
Refinement#{extend_object,append_features,prepend_features}
を削除するチケットRefinement#include/prepend
が削除されるのでもう不要ってことかな?append_features
などはinclude
などの実体- https://docs.ruby-lang.org/ja/latest/method/Module/i/append_features.html
[Feature #18334] ENV#to_h returns a new Hash object but Hash#to_h does not, which can cause inconsistencies
ENV.to_h
は新しいHash
オブジェクトを返すがHash#to_h
はレシーバを返す
# ENV.to_h は異なる object_id になる ENV.to_h.object_id # => 14700 ENV.to_h.object_id # => 14760 # Hash は同じ object_id になる hash = {"FOO" => "bar"} hash.to_h.object_id # => 14820 hash.to_h.object_id # => 14820
ENV
とHash
を両方受け入れる処理がある場合にこの差異があると問題があるんじゃないだろうか、というチケット- 合わせて
self.to_h.dup
を返すENV.dup
を追加しないか、という提案- ちなみに Ruby 3.1 から
ENV.dup
は削除される予定 - [Bug #17767]
Cloned ENV
inconsistently returnsENV
orself
- ちなみに Ruby 3.1 から
- それだと
ENV.dup
がENV
を返さなくなるので他のdup
と矛盾しているとコメントされたりしてる
[Feature #14332] Module.used_refinements to list refinement modules
using
されているRefinement
オブジェクトを返すModule.used_refinements
メソッドを追加する提案
module Json refine Integer do def to_json to_s end end refine String do def to_json inspect end end end module Fact refine Integer do def fact self <= 1 ? 1 : self * (self-1).fact end end end using Json p Module.used_modules # => [Json] # using されている Refinement オブジェクト一覧を返す p Module.used_refinements # => [#<refinement:Integer@Json>, #<refinement:String@Json>] using Fact p Module.used_modules # => [Json, Fact] p Module.used_refinements # => [#<refinement:Integer@Fact>, #<refinement:Integer@Json>, #<refinement:String@Json>]
- あればいろいろとできそうだけど具体的にどういう時に使うのかはわからねえ
[Feature #12737] Module#defined_refinements
- レシーバで定義されている
refine
されたオブジェクトとそのRefinement
オブジェクトのHash
を返すModule#defined_refinements
メソッドを追加する提案
module M refine String do $M_String = self end refine Integer do $M_Integer = self end end p M.defined_refinements #=> {String => $M_String, Integer => $M_Integer}
- これもあれば便利そう
[Bug #18343] empty hash passed to Array#pack causes Segmentation fault (2.6)
# これで segv する [0].pack('c', {})
- Ruby 2.6 は現状セキリュティサポートのみなのでこのチケットは閉じられている
[Feature #18332] a ? b
a ? b : nil
をa ? b
とかけるようにする提案&&
と似てるけどちょっと違うa && b
の場合はfalse
が返ってくる
- ユースケース
"#{current_path == "/" ? "font-bold"}" "#{user.admin? ? "text-red-600"}"
root? ? "font-bold"
と"font-bold" if root?
どっちが読みやすい?みたいなコメントがされている