module Forwardable

TheForwardable module provides delegation of specified methods to a designated object, using the methodsdef_delegator anddef_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'classRecordCollectionattr_accessor:recordsextendForwardabledef_delegator:@records,:[],:record_numberend

We can use the lookup method like so:

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

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

classRecordCollection# re-open RecordCollection classdef_delegators:@records,:size,:<<,:mapendr =RecordCollection.newr.records = [1,2,3]r.record_number(0)# => 1r.size# => 3r<<4# => [1, 2, 3, 4]r.map {|x|x*2 }# => [2, 4, 6, 8]

You can even extend regular objects withForwardable.

my_hash =Hash.newmy_hash.extendForwardable# prepare object for delegationmy_hash.def_delegator"STDOUT","puts"# add delegation for STDOUT.puts()my_hash.puts"Howdy!"

Another example

You could useForwardable 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 ofArray instance methods to a new classQueue:

classQueueextendForwardabledefinitialize@q = [ ]# prepare delegate objectend# setup preferred interface, enq() and deq()...def_delegator:@q,:push,:enqdef_delegator:@q,:shift,:deq# support some general Array methods that fit Queues welldef_delegators:@q,:clear,:first,:push,:shift,:sizeendq =Thread::Queue.newq.enq1,2,3,4,5q.push6q.shift# => 1whileq.size>0putsq.deqendq.enq"Ruby","Perl","Python"putsq.firstq.clearputsq.first

This should output:

23456Rubynil

Notes

Be advised, RDoc will not detect delegated methods.

forwardable.rb provides single-method delegation via thedef_delegator anddef_delegators methods. For full-class delegation via DelegateClass, seedelegate.rb.

Constants

FORWARDABLE_VERSION

Version for backward compatibility

VERSION

Version offorwardable.rb

Attributes

debug[RW]

ignored

Public Instance Methods

Alias for:def_instance_delegator
Alias for:def_instance_delegators
Source
# File lib/forwardable.rb, line 188defdef_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 instancemod =Module===self?self:singleton_classmod.module_eval(&gen)end

Definemethod as delegator instance method with an optional alias nameali. Method calls toali will be delegated toaccessor.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.

classMyQueueCONST =1extendForwardableattr_reader:queuedefinitialize@queue = []enddef_delegator:@queue,:push,:mypushdef_delegator'MyQueue::CONST',:to_iendq =MyQueue.newq.mypush42q.queue#=> [42]q.push23#=> NoMethodErrorq.to_i#=> 1
Also aliased as:def_delegator
Source
# File lib/forwardable.rb, line 156defdef_instance_delegators(accessor,*methods)methods.eachdo|method|nextif/\A__(?:send|id)__\z/=~methoddef_instance_delegator(accessor,method)endend

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,:<<,:mapdef_delegator:@records,:sizedef_delegator:@records,:<<def_delegator:@records,:map
Also aliased as:def_delegators
Alias for:instance_delegate
Source
# File lib/forwardable.rb, line 135definstance_delegate(hash)hash.eachdo|methods,accessor|unlessdefined?(methods.each)def_instance_delegator(accessor,methods)elsemethods.each {|method|def_instance_delegator(accessor,method)}endendend
Also aliased as:delegate