1 # = forwardable - Support for the Delegation Pattern
3 # $Release Version: 1.1$
5 # $Date: 2007-02-12 15:01:19 -0800 (Mon, 12 Feb 2007) $
6 # by Keiju ISHITSUKA(keiju@ishitsuka.com)
8 # Documentation by James Edward Gray II and Gavin Sinclair
12 # This library allows you delegate method calls to an object, on a method by
13 # method basis. You can use Forwardable to setup this delegation at the class
14 # level, or SingleForwardable to handle it at the object level.
18 # Be advised, RDoc will not detect delegated methods.
20 # <b>forwardable.rb provides single-method delegation via the
21 # def_delegator() and def_delegators() methods. For full-class
22 # delegation via DelegateClass(), see delegate.rb.</b>
28 # Forwardable makes building a new class based on existing work, with a proper
29 # interface, almost trivial. We want to rely on what has come before obviously,
30 # but with delegation we can take just the methods we need and even rename them
31 # as appropriate. In many cases this is preferable to inheritance, which gives
32 # us the entire old interface, even if much of it isn't needed.
38 # @q = [ ] # prepare delegate object
41 # # setup prefered interface, enq() and deq()...
42 # def_delegator :@q, :push, :enq
43 # def_delegator :@q, :shift, :deq
45 # # support some general Array methods that fit Queues well
46 # def_delegators :@q, :clear, :first, :push, :shift, :size
58 # q.enq "Ruby", "Perl", "Python"
73 # === SingleForwardable
75 # printer = String.new
76 # printer.extend SingleForwardable # prepare object for delegation
77 # printer.def_delegator "STDOUT", "puts" # add delegation for STDOUT.puts()
78 # printer.puts "Howdy!"
85 # The Forwardable module provides delegation of specified
86 # methods to a designated object, using the methods #def_delegator
87 # and #def_delegators.
89 # For example, say you have a class RecordCollection which
90 # contains an array <tt>@records</tt>. You could provide the lookup method
91 # #record_number(), which simply calls #[] on the <tt>@records</tt>
94 # class RecordCollection
96 # def_delegator :@records, :[], :record_number
99 # Further, if you wish to provide the methods #size, #<<, and #map,
100 # all of which delegate to @records, this is how you can do it:
102 # class RecordCollection
103 # # extend Forwardable, but we did that above
104 # def_delegators :@records, :size, :<<, :map
107 # Also see the example at forwardable.rb.
113 # force Forwardable to show up in stack backtraces of delegated methods
118 # Shortcut for defining multiple delegator methods, but with no
119 # provision for using a different name. The following two code
120 # samples have the same effect:
122 # def_delegators :@records, :size, :<<, :map
124 # def_delegator :@records, :size
125 # def_delegator :@records, :<<
126 # def_delegator :@records, :map
128 # See the examples at Forwardable and forwardable.rb.
130 def def_instance_delegators(accessor, *methods)
131 for method in methods
132 def_instance_delegator(accessor, method)
137 # Defines a method _method_ which delegates to _obj_ (i.e. it calls
138 # the method of the same name in _obj_). If _new_name_ is
139 # provided, it is used as the name for the delegate method.
141 # See the examples at Forwardable and forwardable.rb.
143 def def_instance_delegator(accessor, method, ali = method)
144 accessor = accessor.id2name if accessor.kind_of?(Integer)
145 method = method.id2name if method.kind_of?(Integer)
146 ali = ali.id2name if ali.kind_of?(Integer)
148 module_eval(<<-EOS, "(__FORWARDABLE__)", 1)
149 def #{ali}(*args, &block)
151 #{accessor}.__send__(:#{method}, *args, &block)
153 $@.delete_if{|s| /^\\(__FORWARDABLE__\\):/ =~ s} unless Forwardable::debug
160 alias def_delegators def_instance_delegators
161 alias def_delegator def_instance_delegator
165 # The SingleForwardable module provides delegation of specified
166 # methods to a designated object, using the methods #def_delegator
167 # and #def_delegators. This module is similar to Forwardable, but it works on
168 # objects themselves, instead of their defining classes.
170 # Also see the example at forwardable.rb.
172 module SingleForwardable
174 # Shortcut for defining multiple delegator methods, but with no
175 # provision for using a different name. The following two code
176 # samples have the same effect:
178 # single_forwardable.def_delegators :@records, :size, :<<, :map
180 # single_forwardable.def_delegator :@records, :size
181 # single_forwardable.def_delegator :@records, :<<
182 # single_forwardable.def_delegator :@records, :map
184 # See the example at forwardable.rb.
186 def def_singleton_delegators(accessor, *methods)
187 for method in methods
188 def_singleton_delegator(accessor, method)
193 # Defines a method _method_ which delegates to _obj_ (i.e. it calls
194 # the method of the same name in _obj_). If _new_name_ is
195 # provided, it is used as the name for the delegate method.
197 # See the example at forwardable.rb.
199 def def_singleton_delegator(accessor, method, ali = method)
200 accessor = accessor.id2name if accessor.kind_of?(Integer)
201 method = method.id2name if method.kind_of?(Integer)
202 ali = ali.id2name if ali.kind_of?(Integer)
204 instance_eval(<<-EOS, "(__FORWARDABLE__)", 1)
205 def #{ali}(*args, &block)
207 #{accessor}.__send__(:#{method}, *args,&block)
209 $@.delete_if{|s| /^\\(__FORWARDABLE__\\):/ =~ s} unless Forwardable::debug
216 alias def_delegators def_singleton_delegators
217 alias def_delegator def_singleton_delegator