rubyapi.org

Module

The Forwardable module provides delegation of specified methods to a designated object, using the methods def_delegator and def_delegators.

For example, say you have a class RecordCollection which contains an array @records. You could provide the lookup method record_number(), which simply calls [] on the @records array, like this:

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

We can use the lookup method like so:

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

Further, if you wish to provide the methods size, <<, and map, all of which delegate to @records, this is how you can do it:

class RecordCollection
  def_delegators :@records, :size, :<<, :map
end
r = RecordCollection.new
r.records = [1,2,3]
r.record_number(0)
r.size
r << 4
r.map { |x| x * 2 }

You can even extend regular objects with Forwardable.

my_hash = Hash.new
my_hash.extend Forwardable
my_hash.def_delegator "STDOUT", "puts"
my_hash.puts "Howdy!"

Another example

You could use Forwardable as an alternative to inheritance, when you don’t want to inherit all methods from the superclass. For instance, here is how you might add a range of Array instance methods to a new class Queue:

class Queue
  extend Forwardable
  def initialize
    @q = [ ]
  end
  def_delegator :@q, :push, :enq
  def_delegator :@q, :shift, :deq
  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
while q.size > 0
  puts q.deq
end
q.enq "Ruby", "Perl", "Python"
puts q.first
q.clear
puts q.first

This should output:

2
3
4
5
6
Ruby
nil

Notes

Be advised, RDoc will not detect delegated methods.

forwardable.rb provides single-method delegation via the def_delegator and def_delegators methods. For full-class delegation via DelegateClass, see delegate.rb.

Constants

Version for backward compatibility

Attributes

ignored

Instance Methods

Define method as delegator instance method with an optional alias name ali. Method calls to ali will be delegated to accessor.method. accessor should be a method name, instance variable name, or constant name. Use the full path to the constant if providing the constant name. Returns the name of the method defined.

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
q.push 23
q.to_i

Shortcut for defining multiple delegator methods, but with no provision for using a different name. The following two code samples have the same effect:

def_delegators :@records, :size, :<<, :map
def_delegator :@records, :size
def_delegator :@records, :<<
def_delegator :@records, :map

Takes a hash as its argument. The key is a symbol or an array of symbols. These symbols correspond to method names, instance variable names, or constant names (see def_delegator). The value is the accessor to which the methods will be delegated.

Read the original on rubyapi.org ↗