2020/08/06 今週の気になった bugs.ruby
内容は適当です。
今週と言っても今週みかけたチケットなだけでチケット自体は昔からあるやつもあります。
[Feature #17097] map_min
, map_max
#map_min
#map_max
を追加する提案
# 以下のようなコードを %w[aa b cccc dd].max_by(&:length).length # => 4 %w[aa b cccc dd].map(&:length).max # => 4 # こう記述するイメージ %w[aa b cccc dd].map_max(&:length) # => 4
- 確かにあると便利そうな気がするがこういうのを上げるときりがないような気もする
#filter_map
みたいにパフォーマンスが改善する例があればワンチャン…?
[Bug #17058] Array#delete_if doesn't change array instantly
Array#delete_if
で条件にあった要素を削除する事ができる
a = [1, 2, 3, 4, 5, 6] # 偶数を削除する a.delete_if { |it| it.even? } p a # => [1, 3, 5]
- このメソッドのドキュメントでは『ブロックが呼ばれるたびにレシーバに即座に反映される』と書かれている
- しかし、実際の挙動は
#delete_if
の処理が終わったあとに反映されている
a = [1, 2, 3, 4, 5, 6] # 偶数を削除する a.delete_if { |it| puts "During iteration: #{a}" it.even? } p a # 期待する挙動: # During iteration: [1, 2, 3, 4, 5, 6] # During iteration: [1, 2, 3, 4, 5, 6] # During iteration: [1, 3, 4, 5, 6] # During iteration: [1, 3, 4, 5, 6] # During iteration: [1, 3, 5, 6] # During iteration: [1, 3, 5, 6] # [1, 3, 5] # 実際の動作: # During iteration: [1, 2, 3, 4, 5, 6] # During iteration: [1, 2, 3, 4, 5, 6] # During iteration: [1, 2, 3, 4, 5, 6] # During iteration: [1, 3, 3, 4, 5, 6] # During iteration: [1, 3, 3, 4, 5, 6] # During iteration: [1, 3, 5, 4, 5, 6] # [1, 3, 5]
- この挙動は Ruby 2.2 -> 2.3 で変更された
- ドキュメントのほうが間違っているということでドキュメントが修正されて Closed された
- レシーバを変更中にレシーバを参照するのはよくないっていうやつですねー
[Bug #17096] attr_accessor doesnt work
attr_accessor
がなんかおかしくない?というバグチケ- 挙動がわかりづらいんですが以下のような結果になる
class A def initialize(type:) @type = type end def b p type # => "hoge" p type.nil? # => false type = 'default' if type.nil? # type.nil? が false なのになぜか type = 'default' されてる type # => "default" end private attr_accessor :type end p A.new(type: "hoge").b
- 初見だと意図しない挙動に見えるんですが実は Ruby だと意図する挙動になります
- 実際の挙動は以下の通り
def b # ここは #type メソッドが呼ばれる # なので type.nil? は false p type p type.nil? # この行で暗黙的に type 変数が定義される # 暗黙的に定義された type 変数は nil で初期化される # なので type.nil? == true となり type = 'default' が呼ばれる type = 'default' if type.nil? type end
type = 'default' if type.nil?
がポイントで Ruby の場合はパース時に代入式が存在すると暗黙的にtype
という変数を定義します- 例えば次のように実際には呼ばれてないけど変数は定義される
# if 式の中身が呼ばれなくても変数 a は定義される if false a = 42 end # 変数 a は nil で定義される p a # => nil
- なので次のようにメソッドと同名の変数を定義する場合は注意する必要がある
def value 42 end # メソッドと同名の変数を定義する場合は要注意 # map 内で呼び出す value はメソッドではなくて変数を参照する value = (1..10).map { |it| it.to_s + value.to_s } p value # => ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]
[Feature #17099] Remove boolean argument and warning from Module#attr
Module#attr
は#attr_reader
と同等だが第二引数にtrue
を渡すと書き込み用メソッドも定義される
class X # #hoge だけ定義される attr :hoge # #foo と #foo= が定義される attr :foo, true end
- しかし、第二引数は非推奨で
-W
を付けると警告が出る
class X # warning: optional boolean argument is obsoleted attr :value, true end
- 長らく非推奨だったのでもう消そうという提案
- 実際に削除する前に
-W
を付けないで警告を出すようにしてしまってもいいかも?
[Bug #16695] Stack consistency error when using the return value
x = false; y = (return until x unless x)
だけで segv するらしい- Ruby むずかしいな?