scramble cadenza

技術ネタのガラクタ置き場

ruby でクラスメソッドを委譲する方法

方法

SingleForwardable を使う
require 'forwardable'
class MyFile
  extend SingleForwardable
  def_delegator File, :join
end

MyFile.join('hoge', 'fuga')
#=> "hoge/fuga"

MyFile のクラスメソッドとして File#join っぽい挙動をするメソッドを委譲

別のやり方

クラスメソッドを委譲する方法をもう一つ。 なんと1行で書けます。(require 入れて2行だけど)

require 'delegate' 
SimpleDelegator.new(File).class_eval { class MyFile2 < self; end } 

MyFile2.join('hoge', 'fuga')
#=> "hoge/fuga"

ここまで書いておいてアレだけど、クラスメソッドは特異メソッドなので、それを委譲してしまうのは、きっと良くない兆候。
どうしてかというと「特異メソッド」というのは、そのオブジェクト固有のメソッドを意味するので、委譲して他のクラスでも使えてしまう、というのは如何なものか、と思うわけですよ。
それって特異じゃないやん!っと。

ちょっと黒魔術っぽいですが、色々できますねーというお話。

おまけ

インスタンスメソッドを委譲したいとき

完全に別の話題だけども、クラスメソッドじゃなくて、インスタンスメソッドを委譲したい場合は以下の3パターンを使い分けると良い。

  • extend Forwardable
    • def_delegator, def_delegators で委譲したいものを必要なだけ定義する
  • DelegateClass(klass) を継承させる
    • 全部のインスタンスメソッドが委譲されて、不要なものは undef や オーバーライドで消していく
  • SimpleDelegate で必要な変数だけピンポイントで委譲させる

参考

Rubyist Magazine - 標準添付ライブラリ紹介 【第 6 回】 委譲