2021/10/28 今回の気になった bugs.ruby のチケット
今週は Enumerable#each_cons
と #each_slice
の戻り値の変更がありました。
[PR #1509] Fix Enumerable#each_cons and each_slice to return a receiver
Enumerable#each_cons
とEnumerable#each_slice
の戻り値をレシーバにする PR- 現在は
nil
を返している
- 現在は
- 2017年の PR で最近マージされた
- チケットは特になさそう?
p [1, 2, 3].each_cons(2) {} # Ruby 3.0 => nil # Ruby 3.1 => [1, 2, 3]
[Bug #18268] Behavior change when each_cons
and break ... if false
are combined in Ruby 3.1
each_cons
の戻り値が変わったよーっていうバグ報告- PR #1509 で変更された影響
- これの影響で Rubocop が壊れたらしい
[Feature #16663] Add block or filtered forms of Kernel#caller to allow early bail-out
#caller
に走査できる機能を追加しようという提案- この機能を追加することでスタックトレースを取得する際のオーバーヘッドを軽減させる目的
- 例えば以下のようにブロックを渡すと以下のように利用できる
def find_matching_frame(regex) caller do |frame| # ファイル名が regex にマッチしたら早期 return する return frame if frame.file =~ regex end end
- また以下のように先頭4つを受け取るようにしたりとか
i = 0 ary = [] caller { |x| ary << x i += 1 break if i == 4 }
- この機能に対する PR ができている
- https://github.com/ruby/ruby/pull/5031
#caller
と #caller_locations` にブロック引数を追加する実装
[Feature #14394] Class.descendants
.descendants
はレシーバが『継承されている』クラス/モジュールの一覧を返すメソッドの追加の提案
module A end module B include A end module C include B end A.descendants #=> [A, C, B] B.descendants #=> [B, C] C.descendants #=> [C]
- 実装やパフォーマンス的な懸念?があり
Class#descendants
だけが実装された- https://github.com/ruby/ruby/pull/4974
- 今回必要なユースケースは
Class#descendants
だけで十分だったぽい
class A; end class B < A; end class C < B; end pp A.descendants #=> [B, C] pp B.descendants #=> [C] pp C.descendants #=> []
[Bug #18267] Argument forwarding requires parenthesis on method definitions
def hoge(foo, ...)
をdef hoge foo, ...
みたいに()
を省略したいという提案- パーサ的にめっちゃむずそうな雰囲気があるんだけどどうなんだろう…
- ちなみに
...
引数をすべて別のメソッドに forward する構文
def foo(...) # foo の引数をすべて bar に渡す bar(...) end
[Feature #18275] Add an option to define_method to not capture the surrounding environment
define_method
で定義したメソッドが Ractor から参照できない
def twice(a) a + a end define_method(:twice2) { |a| a + a } ractor = Ractor.new(10) do |loop_count| $stdout.sync = true # def で定義した twice は参照できる p "twice: #{twice loop_count}" # define_method で定義した twice2 は参照できない p "twice2: #{twice2 loop_count}" end ractor.take
- これを解消するために
define_method
に変数などをキャプチャしないようにするオプションを追加する提案- 不要な変数までキャプチャすると遅くなってしまう
- 明示的にキャプチャしないようにすることで Ractor から参照できるようにする
some_random_thing = “a” * 10000 some_captured_block = -> { ... } # capture_environment: でキャプチャするかどうかを制御する define_method(:my_method, capture_environment: false, &some_captured_block)
some_random_thing = “a” * 10000 # kept because `my_method` needs it another_random_thing = “b” * 10000 # not kept some_captured_block = -> { ... } # 特定の変数のみをキャプチャする define_method(:my_method, needs: [:some_random_thing], &some_captured_block)
- これ読んでて記憶でたけど
Ractor.make_shareable
しておけばRactor
で使用可能
# Proc を make_shareable 化しておけば OK body = -> (a) { a + a } Ractor.make_shareable(body) define_method(:twice, &body) ractor = Ractor.new(10) do |loop_count| $stdout.sync = true # twice は参照できる p "twice: #{twice loop_count}" end ractor.take
[Feature #12495] Make "private" return the arguments again, for chaining
private
の戻り値をレシーバから引数を返すようにする提案
class X def hoge p private :hoge # 現在の挙動 => X # 変更する挙動 => :hoge end
- 以下のようなことをやりたい
def cached(name) # Rewrite method to include a cache return name end # これは OK private cached def foo() end # こうもかけるようにしたい cached private def foo() end
- この挙動を
Module#{public,private,protected,module_function}
で実装した PR が投げられている
[Feature #11689] Add methods allow us to get visibility from Method and UnboundMethod object.
- メソッドのアクセシビリティを返す
Method#visibility
UnboundMethod#visibility
を追加する提案:public
:protected
:private
が返ってくる
- ユースケースとしては任意のメソッドをラップする場合に元のメソッドと合わせるために使用できる
class Object def debugging(name) original = instance_method(name) # 提案 method_visibility = original.visibility # 既存の実装だとこう書く必要がある # method_visibility = if private_method_defined?(name) # :private # elsif protected_method_defined?(name) # :protected # else # :public # end define_method(name) { |*args, &block| pp name original.bind(self).call(*args, &block) } # 元のメソッドに合わせる send(method_visibility, name) end end class X def hoge pp 1 + 2 end private :hoge debugging :hoge end # error: private method `hoge' called for #<X:0x000055f0b1abf3e0> (NoMethodError) X.new.hoge
#public?
#protected?
#private?
で判定する実装の PR が投げられた