Ruby 2.4

SimpleDelegator

class SimpleDelegator

Parent:Delegator

Delegator的一个具体实现,该类提供了将所有支持的方法调用委托给传递给构造方法的对象的方法,甚至可以在以后使用#__setobj__更改委派的对象。

class User def born_on Date.new(1989, 9, 10) end end 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__() { || ... } Show source

返回正在委派的当前对象方法调用。

# File lib/delegate.rb, line 309 def __getobj__ unless defined?(@delegate_sd_obj) return yield if block_given? __raise__ ::ArgumentError, "not delegated" end @delegate_sd_obj end

__setobj__(obj) Show source

将委托对象更改为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 331 def __setobj__(obj) __raise__ ::ArgumentError, "cannot delegate to self" if self.equal?(obj) @delegate_sd_obj = obj end