module Forwardable

Das Modul Forwardable bietet die Delegation von angegebenen Methoden an ein bestimmtes Objekt unter Verwendung der Methoden def_delegator und def_delegators.

Angenommen, Sie haben eine Klasse RecordCollection, die ein Array @records enthält. Sie könnten die Lookup-Methode record_number() bereitstellen, die einfach [] auf dem @records-Array aufruft, wie folgt:

require 'forwardable'

class RecordCollection
  attr_accessor :records
  extend Forwardable
  def_delegator :@records, :[], :record_number
end

Wir können die Lookup-Methode wie folgt verwenden:

r = RecordCollection.new
r.records = [4,5,6]
r.record_number(0)  # => 4

Wenn Sie außerdem die Methoden size, << und map bereitstellen möchten, die alle an @records delegiert werden, können Sie dies so tun:

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]

Sie können sogar reguläre Objekte mit Forwardable erweitern.

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!"

Ein weiteres Beispiel

Sie könnten Forwardable als Alternative zur Vererbung verwenden, wenn Sie nicht alle Methoden von der Superklasse erben möchten. Hier ist zum Beispiel, wie Sie einer neuen Klasse Queue eine Reihe von Array-Instanzmethoden hinzufügen könnten:

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

Dies sollte ausgeben:

2
3
4
5
6
Ruby
nil

Hinweise

Beachten Sie, dass RDoc delegierte Methoden nicht erkennt.

forwardable.rb bietet die Einzelmethoden-Delegation über die Methoden def_delegator und def_delegators. Für die Delegationsklasse über DelegateClass siehe delegate.rb.