模块 Forwardable
Forwardable
模块使用 def_delegator
和 def_delegators
方法,将指定的方法委托给指定对象。
例如,假设你有一个类 RecordCollection,它包含一个数组 @records
。你可以提供一个查找方法 record_number(),该方法只是调用 @records
数组的 [],就像这样
require 'forwardable' class RecordCollection attr_accessor :records extend Forwardable def_delegator :@records, :[], :record_number end
我们可以像这样使用查找方法
r = RecordCollection.new r.records = [4,5,6] r.record_number(0) # => 4
此外,如果你希望提供 size、 << 和 map 方法,它们都委托给 @records,你可以这样做
class RecordCollection # re-open RecordCollection class def_delegators :@records, :size, :<<, :map end r = RecordCollection.new r.records = [1,2,3] r.record_number(0) # => 1 r.size # => 3 r << 4 # => [1, 2, 3, 4] r.map { |x| x * 2 } # => [2, 4, 6, 8]
你甚至可以使用 Forwardable
扩展常规对象。
my_hash = Hash.new my_hash.extend Forwardable # prepare object for delegation my_hash.def_delegator "STDOUT", "puts" # add delegation for STDOUT.puts() my_hash.puts "Howdy!"
另一个例子¶ ↑
当你不想继承超类的所有方法时,你可以使用 Forwardable
作为继承的替代方法。例如,这里是如何将一系列 Array
实例方法添加到新类 Queue
的方法
class Queue extend Forwardable def initialize @q = [ ] # prepare delegate object end # setup preferred interface, enq() and deq()... def_delegator :@q, :push, :enq def_delegator :@q, :shift, :deq # support some general Array methods that fit Queues well def_delegators :@q, :clear, :first, :push, :shift, :size end q = Thread::Queue.new q.enq 1, 2, 3, 4, 5 q.push 6 q.shift # => 1 while q.size > 0 puts q.deq end q.enq "Ruby", "Perl", "Python" puts q.first q.clear puts q.first
这应该输出
2 3 4 5 6 Ruby nil
注意事项¶ ↑
请注意,RDoc 不会检测到委托的方法。
forwardable.rb
通过 def_delegator
和 def_delegators
方法提供单方法委托。有关通过 DelegateClass 进行全类委托,请参阅 delegate.rb
。
常量
- FORWARDABLE_VERSION
- VERSION
forwardable.rb
的版本
属性
debug[RW]
忽略
公共实例方法
def_instance_delegator(accessor, method, ali = method) 点击切换源代码
将 method
定义为委托实例方法,可选择别名 ali
。对 ali
的方法调用将委托给 accessor.method
。 accessor
应该是方法名、实例变量名或常量名。如果提供常量名,请使用常量的完整路径。返回定义的方法的名称。
class MyQueue CONST = 1 extend Forwardable attr_reader :queue def initialize @queue = [] end def_delegator :@queue, :push, :mypush def_delegator 'MyQueue::CONST', :to_i end q = MyQueue.new q.mypush 42 q.queue #=> [42] q.push 23 #=> NoMethodError q.to_i #=> 1
# File forwardable.rb, line 188 def def_instance_delegator(accessor, method, ali = method) gen = Forwardable._delegator_method(self, accessor, method, ali) # If it's not a class or module, it's an instance mod = Module === self ? self : singleton_class ret = mod.module_eval(&gen) mod.__send__(:ruby2_keywords, ali) if RUBY_VERSION >= '2.7' ret end
别名为:def_delegator
def_instance_delegators(accessor, *methods) 点击切换源代码
定义多个委托方法快捷方式,但不允许使用不同的名称。以下两个代码示例具有相同的效果
def_delegators :@records, :size, :<<, :map def_delegator :@records, :size def_delegator :@records, :<< def_delegator :@records, :map
# File forwardable.rb, line 156 def def_instance_delegators(accessor, *methods) methods.each do |method| next if /\A__(?:send|id)__\z/ =~ method def_instance_delegator(accessor, method) end end
别名为:def_delegators
instance_delegate [方法, 方法, ...] => accessor 点击切换源代码
将哈希作为参数。键是符号或符号数组。这些符号对应于方法名称、实例变量名称或常量名称(请参阅 def_delegator
)。值是将方法委托到的访问器。
# File forwardable.rb, line 135 def instance_delegate(hash) hash.each do |methods, accessor| unless defined?(methods.each) def_instance_delegator(accessor, methods) else methods.each {|method| def_instance_delegator(accessor, method)} end end end
别名为:delegate