2021/01/14 今週の気になった bugs.ruby のチケット
内容は適当です。
今週と言っても今週みかけたチケットなだけでチケット自体は昔からあるやつもあります。
あくまでも『わたしが気になったチケット』で全ての bugs.ruby のチケットを載せているわけではありません。
[Feature #17485] Keyword argument for timezone in Time.new
Time.new
でタイムゾーンを指定する場合、以下のように時間をすべて指定する必要がある
# OK Time.new(2021, 1, 1, 0, 0, 0, "+09:00") #=> ok: 2021-01-01 00:00:00 +0900 # これは意図するタイムゾーンを設定できない Time.new(2021, 1, 1, "+09:00") #=> bad: 2021-01-01 09:00:00 +0900 Time.new(2021, 1, "+09:00") #=> bad: 2021-01-09 00:00:00 +0900 Time.new(2021, "+09:00") #=> ArgumentError (mon out of range)
- キーワード引数
in
でタイムゾーンを設定できるようにするチケット
Time.new(2021, 1, 1, in: "+09:00") #=> ok: 2021-01-01 00:00:00 +0900 Time.new(2021, in: "+09:00") #=> ok: 2021-01-01 00:00:00 +0900
- 便利そう
- これはすでにマージ済み
[Feature #16806] Struct#initialize accepts keyword arguments too by default
Struct
のkeyword_init:
をデフォルトで有効化させるチケット
User = Struct.new(:name, :age) # これは以前の挙動のまま homu = User.new("homu", 14) # キーワード引数を渡すと keyword_init: true と同じように初期化される homu = User.new(name: "homu", age: 14)
- ただし、以下のようなケースで互換性が壊れるかもしれない
User = Struct.new(:name, :age) # 現状だと name に Hash オブジェクトが入ってしまうので既存の挙動と変わってしまう p User.new(name: "homu", age: 14) # => #<struct User name={:name=>"homu", :age=>14}, age=nil>
- この変更は 3.1 で警告を出すようにして 3.2 で対応される予定になる
[Bug #17519] set_visibility fails when a prepended module and a refinement both exist
- 以下のように
refine
後のメソッドを特異クラスを経由してprivate
化しようとするとエラーになるというバグ報告
module Nothing; end class X # prepend しなかったらエラーにはならない prepend Nothing def hoge end end # これは OK X.new.singleton_class.class_eval { private :hoge } module NeverUsed refine X do def hoge(*keys) end end end # `private': undefined method `hoge' for class `#<Class:#<X:0x0000558fa95b7d70>>' (NameError) # Refinements で拡張したあとに呼ぶとエラーになる X.new.singleton_class.class_eval { private :hoge }
- なにもわからない…
- これは Ruby 2.5, 2.6, 2.7 でも再現していた
[Bug #17533] Named capture is not assigned to the same variable as reserved words.
- 次のように正規表現で任意の変数に結果をキャプチャすることができる
# マッチした部分を result 変数に保存する /(?<result>\d+).*/ =~ "1234hoge" pp result # => "1234"
- この時に予約語をキーワード引数として定義している時に正しく代入されていなかった
def test(nil: :ng) # nil という変数名にマッチしたテキストが代入されるのを期待する # しかし、代入されない /(?<nil>\d+).*/ =~ "1234hoge" binding.local_variable_get(:nil) # => :ng end test
- この問題はすでに修正済み
def test(nil: :ng) /(?<nil>\d+).*/ =~ "1234hoge" binding.local_variable_get(:nil) # 3.0 => :ng # 3.1 => "1234" end test
[Bug #17534] Pattern-matching is broken with find pattern
- 次のような find パターンを含んだパターンマッチでぶっ壊れるという報告
case [1, 2, 3] in y puts "branch1" in [*, x, *] puts "branch2" else puts "branch3" end # output: __END__ -- raw disasm-------- trace: 1 0000 putnil ( 2) 0001 duparray <hidden> ( 1) 0003 dup ( 2) 0004 setlocal_WC_0 4 ( 2) 0006 jump <L002> ( 2) 0008 dup ( 4) 0009 topn 2 ( 4) 0011 opt_le <calldata:<=, 1> ( 4) 0013 branchunless <L013> ( 4) 0015 topn 3 ( 4) 0017 topn 1 ( 4) 0019 opt_aref <calldata:[], 1> ( 4) 0021 setlocal_WC_0 3 ( 4) 0023 jump <L012> ( 4) <L013> [sp: 2] 0025 pop ( 4) 0026 pop ( 4) * 0027 pop ( 4) 0028 jump <L006> ( 4) <L012> [sp: 2] 0030 pop ( 4) 0031 pop ( 4) 0032 pop ( 4) 0033 pop ( 4) 0034 jump <L004> ( 4) <L006> [sp: -1] 0036 pop ( 4) <L001> [sp: -1] 0037 pop ( 7) 0038 pop ( 7) trace: 1 0039 putself ( 7) 0040 putstring "branch3" ( 7) 0042 opt_send_without_block <calldata:puts, 1> ( 7) 0044 leave ( 7) <L002> [sp: 2] 0045 pop ( 2) 0046 pop ( 2) trace: 1 0047 putself ( 3) 0048 putstring "branch1" ( 3) 0050 opt_send_without_block <calldata:puts, 1> ( 3) 0052 leave ( 7) <L004> [sp: -1] 0053 pop ( 4) 0054 pop ( 4) trace: 1 0055 putself ( 5) 0056 putstring "branch2" ( 5) 0058 opt_send_without_block <calldata:puts, 1> ( 5) 0060 leave ( 7) --------------------- /tmp/vxdawqc/180:4: warning: Find pattern is experimental, and the behavior may change in future versions of Ruby! /tmp/vxdawqc/180:4: argument stack underflow (-1) /tmp/vxdawqc/180: compile error (SyntaxError)
- こんなエラーはじめてみた…
- 結構簡単に再現しそうなので怖い
[Feature #13683] Add strict Enumerable#single
- レシーバの要素を1つだけ返す
Enumerable#single
を追加する提案 - 似たようなメソッドに
Enumerable#first
があるがちょっと意味が違うEnumerable#first
: 先頭の要素を返す。見つからなかった場合はnil
を返すEnumerable#single
: 先頭の要素を返す。ただし、要素が2個以上、または存在しない場合は例外を発生させる
- あんまり利便性がわからないけど便利なのかな…?
- ちなみに ActiveSupport にも同様の PR が投げられてます
- https://github.com/rails/rails/pull/26206
- こっちは close されている
- 現状は
#single
という名前ではなくて違う名前の方がいいんじゃないか、みたいな名前付けの議論で止まってるぽい - と、思ってたら ActiveRecord で同じような機能の
ActiveRecord::FinderMethods#sole
というメソッドが追加されました- https://github.com/rails/rails/pull/40768
- こっちは
#sole
っていう名前になったぽい。別名で#find_by_sole
もあるみたいですが
- 更に ActiveSupport で
Enumerable#sole
を追加する PR もある- https://github.com/rails/rails/pull/40914
- こっちはまだマージされていない
- ActiveSupport で
Enumerable#sole
が追加されたあとに Ruby の標準に別名で同等の機能が入った場合、混乱しそうだなあ - ちなみにパターンマッチで取得するのはどうか、というコメントもされている
- https://bugs.ruby-lang.org/issues/13683#note-32
- 個人的にはこの書き方が好き
case []; in [a]; p a; end #=> NoMatchingPatternError ([]) case [1]; in [a]; p a; end #=> 1 case [1,2]; in [a]; p a; end #=> NoMatchingPatternError ([1, 2])