JanGaJan.com

Is fun? JOY!

Rubyとrailsのdelegate

委譲があまりよくわかっていなかったのでメモ。継承よりは使いやすそう。

rubyのdelegate

Forwardableクラスに委譲のメソッドがあります。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
require 'forwardable'

class Hoge
  extend Forwardable

  # also: def_delegators :@delegator, :name, :age
  delegate [:name, :age] => :@delegator

  def initialize args
    @delegator = args == 'nakachi' ? Nakachi.new : Tanaka.new
  end

  class Nakachi
    def name; 'I am Nakachi' end
    def age; 100 end
  end

  class Tanaka
    def name; 'I am Tanaka' end
    def age; 10 end
  end
end

hoge = Hoge.new 'nakachi'
puts hoge.name #=> 'I am Nakachi'
puts hoge.age  #=> 100

railsのdelegate

activesupportでModuleのインスタンスメソッドとして定義されています。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
require 'active_support'
require 'active_support/core_ext'

module DelegatorFuga
  delegate :name, :age, to: :delegator

  class Nakachi
    def name; 'I am Nakachi' end
    def age; 100 end
  end

  class Tanaka
    def name; 'I am Tanaka' end
    def age; 10 end
  end
end

class Fuga
  include DelegatorFuga

  attr_reader :delegator

  def initialize args
    @delegator = args == 'nakachi' ? DelegatorFuga::Nakachi.new : DelegatorFuga::Tanaka.new
  end
end

fuga = Fuga.new 'nakachi'
puts fuga.name #=> 'I am Nakachi'
puts fuga.age  #=> 100

こっちには、prefixallow_nilというオプションがある。

allow_nil

委譲先がnilの場合でもメソッド呼び出し時にnilを返してくれるようになる。

1
2
3
4
5
6
7
> delegate :name, :age, to: :delegator, allow_nil: true
> @delegator = args == 'nakachi' ? nil : DelegatorFuga::Tanaka.new

fuga = Fuga.new 'nakachi'
# method_missingは発生しない
puts fuga.name #=> nil
puts fuga.age  #=> nil

prefix

delegateしたメソッドのprefixをつける。この場合、prefixをつけない形式でメソッドを呼び出すことはできなくなる。

1
2
3
4
5
> delegate :name, :age, to: :delegator, prefix: true

fuga = Fuga.new 'nakachi'
puts fuga.delegator_name
puts fuga.delegator_age
1
2
3
4
5
> delegate :name, :age, to: :delegator, prefix: :my

fuga = Fuga.new 'nakachi'
puts fuga.my_name
puts fuga.my_age

Comments