🔥

【Ruby 3.4 Advent Calender】Refinement#refined_class が削除された【22日目】

2024/12/22に公開

Ruby 3.4 Advent Calender 22日目の記事です。

これはなに

今年 2024年12月25日にリリースされる予定の Ruby 3.4 の新機能や変更点などを1つずつ紹介していく Advent Calender になります。
基本的には NEWS に載っている機能を紹介すると思うんですがここにない機能についても書くかもしれません。
また、記事を書いてる時点ではまだ Ruby 3.4 はリリースされる前なので Ruby 3.4 がリリースされた時点で機能が変わっている 可能性があるかもしれないので注意してください。
記事のまとめは ここを参照 してください。

Refinement#refined_class が削除された

Ruby 3.4 以前では refine されているクラスを取得する Refinement#refined_class メソッドがありました。
例えば refine のブロック内から refine されているオブジェクトを #refined_class メソッドで取得することができました。

module Ext
  refine String do
    # refine されているオブジェクトを取得できる
    pp refined_class # => String
  end

  refine String.singleton_class do
    # singleton_class みたいなのも取得できる
    pp refined_class # => #<Class:String>
  end
end

この #refined_class メソッドが Ruby 3.4 では削除されました。
変わりに Ruby 3.3 から追加された Refinement#target メソッドが利用できます。

module Ext
  refine String do
    # #refined_class と同じ値を返す
    pp target # => String
  end
end

Refinement#refined_class を使用している場合は使用するメソッドを変更する必要があるので注意してください。

背景

#refined_class という名前のメソッドなんですが実際には『 class ではなくて module オブジェクトを返す』ケースも存在しています。
例えば以下のように refinemodule を渡した場合ですね。

module Ext
  # module オブジェクトに対して refine した場合は当然 module のオブジェクトが返ってくる
  refine Enumerable do
    pp refined_class
  end
end

これが名前と実態があっていないということで以下のチケットで Refinement#refined_module を追加する提案がされました。

最終的にこのチケットでは Ruby 3.3 では以下の対応がされることが決定しました。

  • Ruby 3.3 で #refined_class と同等の #target という名前のメソッドを追加する
  • Ruby 3.3 では #refined_class を使用すると警告を出すようにする
    • -W:deprecated が有効な場合に警告がでる
  • Ruby 3.4 では #refined_class を削除する

なので Ruby 3.3 では以下のような挙動になります

Warning[:deprecated] = true

module Ext
  refine Enumerable do
    # no warning
    pp target # => Enumerable

    # warning: Refinement#refined_class is deprecated and will be removed in Ruby 3.4; use Refinement#target instead
    pp refined_class # => Enumerable
  end
end

関連

GitHubで編集を提案

Discussion