🙂
RailsじゃないRubyでRailsっぽくdelegateする
Railsのdelegate
メソッドは便利ですよね。
- https://railsguides.jp/active_support_core_extensions.html#delegate
- https://api.rubyonrails.org/classes/Module.html#method-i-delegate
Rails以外のRubyコードでもdelegate
を使いたくなりますが、そのためにActiveSupportを導入するのもちょっと…という場合のために、シンプルなモジュールを作ってみます。
使い方
Delegatable
というモジュールにしてみます。クラスの中でextend Delegatable
すると、そのクラス内でdelegate
メソッドが使えるようになります。
以下のように使えるものです。
delegate :metohd1, :method2, ... methodn, to: :target
こうすると、method1
やmethod2
を呼び出すと、それらが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があります。そちらも合わせて検討すると良いでしょう。
- 標準添付ライブラリ紹介 【第6回】 委譲 (Rubyist Magazine、西山さん) https://magazine.rubyist.net/articles/0012/0012-BundledLibraries.html
Discussion