Delegator 類別

此函式庫提供三種不同的方式將方法呼叫委派給物件。最容易使用的是 SimpleDelegator。將物件傳遞給建構函式,物件支援的所有方法都將被委派。此物件稍後可以變更。

更進一步,頂層 DelegateClass 方法允許您輕鬆透過類別繼承設定委派。這靈活得多,因此可能是此函式庫最常見的用途。

最後,如果您需要完全控制委派方案,您可以從抽象類別 Delegator 繼承並依需要自訂。(如果您發現自己需要這種控制,請查看標準函式庫中的 Forwardable。它可能更適合您的需求。)

SimpleDelegator 的實作作為 Delegator 使用的一個好範例

require 'delegate'

class SimpleDelegator < Delegator
  def __getobj__
    @delegate_sd_obj # return object we are delegating to, required
  end

  def __setobj__(obj)
    @delegate_sd_obj = obj # change delegation object,
                           # a feature we're providing
  end
end

備註

請注意,RDoc 無法偵測委派方法。

常數

KERNEL_RESPOND_TO
VERSION

公開類別方法

new(obj) 按一下以切換來源

傳入要將方法呼叫委派給的 objobj 支援的所有方法都將被委派。

# File lib/delegate.rb, line 75
def initialize(obj)
  __setobj__(obj)
end

公開實例方法

!() 按一下以切換來源

將 ! 委派給 _getobj_

# File lib/delegate.rb, line 180
def !
  !__getobj__
end
!=(obj) 按一下以切換來源

如果兩個物件不被視為等值,則傳回 true。

# File lib/delegate.rb, line 164
def !=(obj)
  return false if obj.equal?(self)
  __getobj__ != obj
end
==(obj) 按一下以切換來源

如果兩個物件被視為等值,則傳回 true。

# File lib/delegate.rb, line 156
def ==(obj)
  return true if obj.equal?(self)
  self.__getobj__ == obj
end
__getobj__() 按一下以切換原始碼

子類別必須覆寫此方法,並傳回物件方法呼叫委派到的目標。

# File lib/delegate.rb, line 188
def __getobj__
  __raise__ ::NotImplementedError, "need to define `__getobj__'"
end
__raise__()
別名:raise
__setobj__(obj) 按一下以切換原始碼

子類別必須覆寫此方法,並將物件委派變更為 obj

# File lib/delegate.rb, line 196
def __setobj__(obj)
  __raise__ ::NotImplementedError, "need to define `__setobj__'"
end
eql?(obj) 按一下以切換原始碼

如果兩個物件被視為等值,則傳回 true。

# File lib/delegate.rb, line 172
def eql?(obj)
  return true if obj.equal?(self)
  obj.eql?(__getobj__)
end
freeze() 按一下以切換原始碼

:method: freeze 凍結 _getobj_ 傳回的物件和 self。

呼叫超類別方法
# File lib/delegate.rb, line 237
def freeze
  __getobj__.freeze
  super()
end
marshal_dump() 按一下以切換原始碼

_getobj_ 傳回的物件的序列化支援。

# File lib/delegate.rb, line 203
def marshal_dump
  ivars = instance_variables.reject {|var| /\A@delegate_/ =~ var}
  [
    :__v2__,
    ivars, ivars.map {|var| instance_variable_get(var)},
    __getobj__
  ]
end
marshal_load(data) 按一下以切換原始碼

從序列化物件重新初始化委派。

# File lib/delegate.rb, line 215
def marshal_load(data)
  version, vars, values, obj = data
  if version == :__v2__
    vars.each_with_index {|var, i| instance_variable_set(var, values[i])}
    __setobj__(obj)
  else
    __setobj__(data)
  end
end
method_missing(m, *args, &block) 按一下以切換原始碼
呼叫超類別方法 BasicObject#method_missing
# File lib/delegate.rb, line 82
               def method_missing(m, *args, &block)
  r = true
  target = self.__getobj__ {r = false}

  if r && target_respond_to?(target, m, false)
    target.__send__(m, *args, &block)
  elsif ::Kernel.method_defined?(m) || ::Kernel.private_method_defined?(m)
    ::Kernel.instance_method(m).bind_call(self, *args, &block)
  else
    super(m, *args, &block)
  end
end
methods(all=true) 按一下以切換原始碼

傳回此委派物件可用的方法,為此物件和 _getobj_ 方法的聯集。

呼叫超類別方法
# File lib/delegate.rb, line 131
def methods(all=true)
  __getobj__.methods(all) | super
end
protected_methods(all=true) 按一下以切換原始碼

傳回此委派物件可用的方法,為此物件和 _getobj_ 受保護方法的聯集。

呼叫超類別方法
# File lib/delegate.rb, line 147
def protected_methods(all=true)
  __getobj__.protected_methods(all) | super
end
public_methods(all=true) 按一下以切換原始碼

傳回此委派物件可用的方法,為此物件和 _getobj_ 公用方法的聯集。

呼叫超類別方法
# File lib/delegate.rb, line 139
def public_methods(all=true)
  __getobj__.public_methods(all) | super
end
raise() 按一下以切換原始碼

如果 Delegator 沒有物件可委派 raise 方法呼叫,請使用 __raise__

# File lib/delegate.rb, line 66
  
別名:__raise__
respond_to_missing?(m, include_private) 按一下以切換原始碼

透過轉送呼叫至 _getobj_,檢查委派物件提供的某個方法。

# File lib/delegate.rb, line 99
def respond_to_missing?(m, include_private)
  r = true
  target = self.__getobj__ {r = false}
  r &&= target_respond_to?(target, m, include_private)
  if r && include_private && !target_respond_to?(target, m, false)
    warn "delegator does not forward private method \##{m}", uplevel: 3
    return false
  end
  r
end

私人執行個體方法

target_respond_to?(target, m, include_private) 按一下以切換原始碼

處理 BasicObject 執行個體

# File lib/delegate.rb, line 114
        def target_respond_to?(target, m, include_private)
  case target
  when Object
    target.respond_to?(m, include_private)
  else
    if KERNEL_RESPOND_TO.bind_call(target, :respond_to?)
      target.respond_to?(m, include_private)
    else
      KERNEL_RESPOND_TO.bind_call(target, m, include_private)
    end
  end
end