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_ 返回的对象和自身。

调用超类方法
# 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