LoginSignup
1
0

More than 5 years have passed since last update.

同じメソッドをインスタンスメソッドにもクラスメソッドにも利用したい場合

Posted at

移譲

module Forwardableを使います。
ForwardableはRubyの標準ライブラリです。

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

オブジェクトの機能を再利用する手法の一つとして、Ruby では言語仕様としてクラスの継承とモジュールの Mix-in を提供しています。これらは、元になるクラスやモジュールの実装までもをそのまま取り込んでしまいますが、他の手段で機能の再利用を実現する手法として、委譲があります。

委譲では、再利用したい機能を自分に取り込むのではなく、その機能を持つオブジェクトに処理を依頼します。

Ruby では特に言語仕様として委譲がサポートされているわけではありませんが、委譲を実現するためのライブラリとして forwardableとdelegate が用意されています。具体的には、これらのライブラリを使用することによって、あるメソッド呼び出しを他のオブジェク>トのメソッドにたらい回すということを簡単に記述することができます。

インスタンスメソッドに移譲

class Outer
  extend Forwardable
  def_delegators :@inner, :hello

  def initialize
    @inner = Inner.new
  end

  class Inner
    extend Forwardable
    def_delegators :hello

    def hello
      puts "hello, world!!"
    end
  end
end

obj = Outer.new
obj.hello  #=> "hello, world!!"

Outer::InnerのインスタンスメソッドをOuterのインスタンスメソッドに移譲したので、どちらもインスタンスメソッドです。

Outer.instance_methods(false)
#=> [:hello]
Outer::Inner.instance_methods(false)
#=> [:hello]

クラスメソッドに移譲

以下のサンプルでは、Innerクラスの中身は全く変わっていないことに注目してください。

require 'forwardable'

class Outer
  class << self
    extend Forwardable
    def_delegators :inner, :hello

    def inner
      Inner.new
    end
  end

  class Inner
    extend Forwardable
    def_delegators :hello

    def hello
      puts "hello, world!!"
    end
  end
end

Outer.hello  #=> hello, world!!

Innerクラスのhelloメソッドはプライベートメソッドですが、Outerクラスではクラスメソッドになっています。

Outer.methods(false)
#=> [:inner, :hello]
Outer::Inner.methods(false)
#=> []
Outer::Inner.instance_methods(false)
#=> [:hello]

さいごに

gimeiのコードを追っていて、どうしてincludeextendを普通に使わないのだろう?
と思ったのがこの記事を書くきっかけとなりました。

gimeiを詠む

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0