類別 SimpleDelegator

作為 Delegator 的具體實作,此類別提供方法,可將所有支援的方法呼叫委派給建構函式中傳入的物件,甚至可以使用 __setobj__ 來變更委派到的物件。

class User
  def born_on
    Date.new(1989, 9, 10)
  end
end

require 'delegate'

class UserDecorator < SimpleDelegator
  def birth_year
    born_on.year
  end
end

decorated_user = UserDecorator.new(User.new)
decorated_user.birth_year  #=> 1989
decorated_user.__getobj__  #=> #<User: ...>

SimpleDelegator 執行個體可以利用 SimpleDelegatorDelegator 子類別的事實,呼叫 super 來對委派到的物件呼叫方法。

class SuperArray < SimpleDelegator
  def [](*args)
    super + 1
  end
end

SuperArray.new([1])[0]  #=> 2

以下是一個簡單範例,利用 SimpleDelegator 的委派物件可以隨時變更的事實。

class Stats
  def initialize
    @source = SimpleDelegator.new([])
  end

  def stats(records)
    @source.__setobj__(records)

    "Elements:  #{@source.size}\n" +
    " Non-Nil:  #{@source.compact.size}\n" +
    "  Unique:  #{@source.uniq.size}\n"
  end
end

s = Stats.new
puts s.stats(%w{James Edward Gray II})
puts
puts s.stats([1, 2, 3, nil, 4, 5, 1, 2])

列印

Elements:  4
 Non-Nil:  4
  Unique:  4

Elements:  8
 Non-Nil:  7
  Unique:  6

公開執行個體方法

__getobj__() { || ... } 按一下以切換來源

傳回目前委派方法呼叫的物件。

# File lib/delegate.rb, line 318
def __getobj__
  unless defined?(@delegate_sd_obj)
    return yield if block_given?
    __raise__ ::ArgumentError, "not delegated"
  end
  @delegate_sd_obj
end
__setobj__(obj) 按一下以切換來源

將委派物件變更為 obj

請務必注意,這不會導致 SimpleDelegator 的方法變更。因此,您可能只想要將委派變更為與原始委派相同類型的物件。

以下是一個變更委派物件的範例。

names = SimpleDelegator.new(%w{James Edward Gray II})
puts names[1]    # => Edward
names.__setobj__(%w{Gavin Sinclair})
puts names[1]    # => Sinclair
# File lib/delegate.rb, line 340
def __setobj__(obj)
  __raise__ ::ArgumentError, "cannot delegate to self" if self.equal?(obj)
  @delegate_sd_obj = obj
end