Ruby の refinements で特異メソッドを定義する時の注意

さて、次のようにクラスオブジェクトに対して特異メソッドを定義するとエラーになります。

module StringEx
  refine String do
    class << self
      def homu
        "homu"
      end
    end
  end
end

using StringEx

# Error: undefined method `homu' for String:Class (NoMethodError)
p String.homu

つい、通常のクラスと同じように class << self を行いたくなるんですが、これでは上手く動作しません。 ここでいう selfstring ではなくて refinement のオブジェクトでラップされた String なので、これでは String に特異メソッドは定義されないからです。

[String.singleton_class を使う]

なので、self ではなくて String.singleton_class を使用すると動作します。

module StringEx
  refine String.singleton_class do
    def homu
      "homu"
    end
  end
end

module M
  using StringEx

  # OK 呼び出せる
  p String.homu
  # => "homu"
end


module M2
  # NG 呼び出せない
  # error: undefined method `homu' for String:Class (NoMethodError)
  p String.homu
end

これでおっけー