🙂

RailsじゃないRubyでRailsっぽくdelegateする

2025/01/12に公開

Railsのdelegateメソッドは便利ですよね。

Rails以外のRubyコードでもdelegateを使いたくなりますが、そのためにActiveSupportを導入するのもちょっと…という場合のために、シンプルなモジュールを作ってみます。

使い方

Delegatableというモジュールにしてみます。クラスの中でextend Delegatableすると、そのクラス内でdelegateメソッドが使えるようになります。

以下のように使えるものです。

delegate :metohd1, :method2, ... methodn, to: :target

こうすると、method1method2を呼び出すと、それらがtargetに移譲されるようになります。

以下が実際に使ってみたサンプルです。

class Foo
  extend Delegatable

  def initialize(items)
    @items = items
  end

  attr_reader :items

  delegate :size, :first, to: :items
end

# ...

foo = Foo.new([:a,:b,:c])
pp foo.size #=> 3
pp foo.first #=> :a

ActiveSupportのdelegateにはallow_nilとかprefixとかのオプションもあるのですが、複雑になるので使わないことにします。

実装

こんな感じで実装できます。

  module Delegatable
    def delegate(*methods, to:)
      methods.each do |method|
        define_method(method) do |*args, **kargs, &block|
          target = send(to)
          target.public_send(method, *args, **kargs, &block)
        end
      end
    end
  end

見ての通り、sendとかpublic_sendとかを使っているので要注意です。変数等は渡さずシンボルリテラルのみを指定して使うのがおすすめです。

備考

なお、標準ライブラリにもforwardableやdelegateがあります。そちらも合わせて検討すると良いでしょう。

Discussion