2020/11/26 今週の気になった bugs.ruby のチケット
内容は適当です。
今週と言っても今週みかけたチケットなだけでチケット自体は昔からあるやつもあります。
あくまでも『わたしが気になったチケット』で全ての bugs.ruby のチケットを載せているわけではありません。
[Bug #7844] include/prepend satisfiable module dependencies are not satisfied
- 以下のような複雑な継承を行った際に意図する継承リストになっていないというバグ報告
- ポイントとしては
A
の前にR
が出てきたりするのがおかしくなっていた- 解説するのは難しいから実際に脳内で考えてみてね!
module P end module Q include P end module R prepend Q end module S include R end class A include S prepend P end p A.ancestors # Ruby 2.7 => [P, R, A, S, Q, Object, Kernel, BasicObject] # Ruby 3.0 => [P, A, S, Q, R, Object, Kernel, BasicObject]
- このバグは修正済み
- 継承周りは他にも Ruby 3.0 で変更点があるのでちょっと気になる
[Bug #10845] Subclassing String
- 以前も紹介したが
String
を継承したクラスで特定のメソッドを呼ぶとString
を返したり継承したクラスを返したりバラバラになっている
class MyString < String end # これは MyString のインスタンスを返す p MyString.new("hoge").capitalize.class # => MyString p MyString.new("hoge").strip.class # => MyString # 以下のメソッドは String のインスタンスを返す p (MyString.new("foo") + "bar").class # => String p (MyString.new("%d") % 42).class # => String
- これに対して
String
に統一するような対処がされた- すでにマージ済み
class MyString < String end # 最新版だと以下の結果になる p MyString.new("hoge").capitalize.class # => String p MyString.new("hoge").strip.class # => String p (MyString.new("foo") + "bar").class # => String p (MyString.new("%d") % 42).class # => String
- 具体的にどのメソッドが対処されたのかは以下の PR を参照
- またこの影響で
ActiveSupport::SafeBuffer
が壊れたらしい`ActiveSupport::SafeBuffer
は#[]
や#*
を再定義しており、その戻り値のクラスが変わったことに対して壊れていた- 修正PR : https://github.com/rails/rails/pull/40663
- 一応、非互換な変更なので注意したい
[Feature #17336] using refined: do ... end
Foo
クラス内でのみ使用できるように拡張する場合、using
に直接Module.new
を渡すことがある
class Foo # Foo 内でのみ Array#flat_map! が使える using Module.new { refine Array do def flat_map!(&block) replace(flat_map(&block)) end end } end
- 上記の書き方ではネストが深くなってしまう
- これを解決する案として以下のように
Kernel#refined
メソッドを経由してネストしないでかけるようにするアイディアもあった
module Kernel # 実装イメージ def refined(mod, &block) Module.new do refine(mod, &block) end end end class Foo # これは refined のブロック引数になる using refined(Array) { def flat_map!(&block) replace(flat_map(&block)) end } # これは using のブロック引数になる using refined(Array) do def flat_map!(&block) replace(flat_map(&block)) end end end
- しかし、上記の場合だと
do ~ end
でかくとusing
メソッドのブロック引数になってしまう問題がある
class Foo # これは using のブロック引数になる using refined(Array) do def flat_map!(&block) replace(flat_map(&block)) end end end
- 以下のようにして
do ~ end
で受け取れるようにするのはどうだろうか、という提案
class Foo using refined: Array do def flat_map!(&block) replace(flat_map(&block)) end end end
- もっと簡単に解決できないかな?と思っていたけど
do ~ end
と{}
でブロックを渡すメソッドが変わるのが結構つらい - 他にも似たようなチケットがあり他の人も書きたい気持ちはあるんだろうけどなかなかいい書き方を見つけるのはむずかしそう…
- このチケットは Feature #16241 に引き継がれて close されてるっぽい
- このあたりはいい感じに書きたい気持ちはあるので一回自分でも考えてみたい
[Feature #17339] Semantic grouping with BigDecimal#to_s
BigDecimal#to_s
では以下のように引数で返ってくる文字列を制御する事ができる
require "bigdecimal" # 引数がない場合は指数形式 p BigDecimal('1234567').to_s # => "0.1234567e7" # 引数が "F" だと指数なしになる p BigDecimal('1234567').to_s('F') # => "1234567.0"
- また、
"3F"
のようにすることで任意の文字数で空白区切りすることができる
require "bigdecimal" # 数値を付けると文字数ごとに空白で区切られる # これは `先頭` を基準として区切られる p BigDecimal('1234567').to_s('3F') # => "123 456 7.0" # 小数が含まれる場合 p BigDecimal('1234567.8901234').to_s('3F') # => "123 456 7.890 123 4"
- このチケットでは
"3F"
を渡したときに区切られる場所を以下のように変更しようという提案になる
# `先頭` からではなくて小数点からの文字数で区切るようにする提案 p BigDecimal('1234567').to_s('3F') # => "1 234 567.0" # 小数が含まれる場合 p BigDecimal('1234567.8901234').to_s('3F') # => "1 234 567.890 123 4"
- また長期的に上記のような挙動をデフォルトにしようという提案も含まれているa
- 国際単位系に準じると提案したような区切りにするのが正しいぽい?
- チケットにも書いてあるけどよくわからねえ…
"F"
ではなくて"G"
という新しいオプションで制御する話もでてる
[Bug #17216] Enumerator::Chain doesn't support all Enumerator methods
Enumerable#chain
を使用すると複数のEnumerator
を 1つのEnumerator
として扱うことができる
p [1, 2, 3].chain((4..5), "a".."c").to_a # => [1, 2, 3, 4, 5, "a", "b", "c"]
Enumerable#chain
はEnumerator::Chain
のインスタンスを返すのだがEnumerator::Chain#with_index
を呼び出すとエラーになってしまうというバグ報告
# error: wrong argument type chain (expected enumerator) (TypeError) [1, 2, 3].chain([4, 5, 6]).with_index.to_a # each を経由すると OK [1, 2, 3].chain([4, 5, 6]).each.with_index.to_a
- この問題はすでに PR が投げられている
merge, fix されたチケット
- [Bug #7844] include/prepend satisfiable module dependencies are not satisfied
- 継承が意図してなかったバグ
- [Bug #11213] defined?(super) ignores respond_to_missing?
defined?(super)
が#respond_to_missing?
を考慮しないバグチケ
- [Bug #10845] Subclassing String
String
を継承したクラスで特定のメソッドを呼ぶとString
を返したり継承したクラスを返したりバラバラになっているのがString
に統一された