~ubuntu-branches/ubuntu/hardy/ruby1.8/hardy-updates

« back to all changes in this revision

Viewing changes to lib/forwardable.rb

  • Committer: Bazaar Package Importer
  • Author(s): akira yamada
  • Date: 2007-03-13 22:11:58 UTC
  • mfrom: (1.1.5 upstream)
  • Revision ID: james.westby@ubuntu.com-20070313221158-h3oql37brlaf2go2
Tags: 1.8.6-1
* new upstream version, 1.8.6.
* libruby1.8 conflicts with libopenssl-ruby1.8 (< 1.8.6) (closes: #410018)
* changed packaging style to cdbs from dbs.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# = forwardable - Support for the Delegation Pattern
 
2
#
 
3
#    $Release Version: 1.1$
 
4
#    $Revision: 11708 $
 
5
#    $Date: 2007-02-13 08:01:19 +0900 (Tue, 13 Feb 2007) $
 
6
#    by Keiju ISHITSUKA(keiju@ishitsuka.com)
 
7
#
 
8
#    Documentation by James Edward Gray II and Gavin Sinclair
 
9
#
 
10
# == Introduction
 
11
#
 
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.
 
15
#
 
16
# == Notes
 
17
#
 
18
# Be advised, RDoc will not detect delegated methods.
 
19
#
 
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>
 
23
#
 
24
# == Examples
 
25
#
 
26
# === Forwardable
 
27
#
 
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.
 
33
#
 
34
#   class Queue
 
35
#     extend Forwardable
 
36
#     
 
37
#     def initialize
 
38
#       @q = [ ]    # prepare delegate object
 
39
#     end
 
40
#     
 
41
#     # setup prefered interface, enq() and deq()...
 
42
#     def_delegator :@q, :push, :enq
 
43
#     def_delegator :@q, :shift, :deq
 
44
#     
 
45
#     # support some general Array methods that fit Queues well
 
46
#     def_delegators :@q, :clear, :first, :push, :shift, :size
 
47
#   end
 
48
 
49
#   q = Queue.new
 
50
#   q.enq 1, 2, 3, 4, 5
 
51
#   q.push 6
 
52
 
53
#   q.shift    # => 1
 
54
#   while q.size > 0
 
55
#     puts q.deq
 
56
#   end
 
57
 
58
#   q.enq "Ruby", "Perl", "Python"
 
59
#   puts q.first
 
60
#   q.clear
 
61
#   puts q.first
 
62
#
 
63
# <i>Prints:</i>
 
64
#
 
65
#   2
 
66
#   3
 
67
#   4
 
68
#   5
 
69
#   6
 
70
#   Ruby
 
71
#   nil
 
72
#
 
73
# === SingleForwardable
 
74
#
 
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!"
 
79
#
 
80
# <i>Prints:</i>
 
81
#
 
82
#    Howdy!
 
83
 
 
84
#
 
85
# The Forwardable module provides delegation of specified
 
86
# methods to a designated object, using the methods #def_delegator
 
87
# and #def_delegators.
 
88
#
 
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>
 
92
# array, like this:
 
93
#
 
94
#   class RecordCollection
 
95
#     extend Forwardable
 
96
#     def_delegator :@records, :[], :record_number
 
97
#   end
 
98
#
 
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:
 
101
#
 
102
#   class RecordCollection
 
103
#     # extend Forwardable, but we did that above
 
104
#     def_delegators :@records, :size, :<<, :map
 
105
#   end
 
106
#
 
107
# Also see the example at forwardable.rb.
 
108
#
 
109
module Forwardable
 
110
 
 
111
  @debug = nil
 
112
  class<<self
 
113
    # force Forwardable to show up in stack backtraces of delegated methods
 
114
    attr_accessor :debug
 
115
  end
 
116
 
 
117
  #
 
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:
 
121
  #
 
122
  #   def_delegators :@records, :size, :<<, :map
 
123
  #
 
124
  #   def_delegator :@records, :size
 
125
  #   def_delegator :@records, :<<
 
126
  #   def_delegator :@records, :map
 
127
  #
 
128
  # See the examples at Forwardable and forwardable.rb.
 
129
  #
 
130
  def def_instance_delegators(accessor, *methods)
 
131
    for method in methods
 
132
      def_instance_delegator(accessor, method)
 
133
    end
 
134
  end
 
135
 
 
136
  #
 
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.
 
140
  #
 
141
  # See the examples at Forwardable and forwardable.rb.
 
142
  #
 
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)
 
147
 
 
148
    module_eval(<<-EOS, "(__FORWARDABLE__)", 1)
 
149
      def #{ali}(*args, &block)
 
150
        begin
 
151
          #{accessor}.__send__(:#{method}, *args, &block)
 
152
        rescue Exception
 
153
          $@.delete_if{|s| /^\\(__FORWARDABLE__\\):/ =~ s} unless Forwardable::debug
 
154
          Kernel::raise
 
155
        end
 
156
      end
 
157
    EOS
 
158
  end
 
159
 
 
160
  alias def_delegators def_instance_delegators
 
161
  alias def_delegator def_instance_delegator
 
162
end
 
163
 
 
164
#
 
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.
 
169
#
 
170
# Also see the example at forwardable.rb.
 
171
#
 
172
module SingleForwardable
 
173
  #
 
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:
 
177
  #
 
178
  #   single_forwardable.def_delegators :@records, :size, :<<, :map
 
179
  #
 
180
  #   single_forwardable.def_delegator :@records, :size
 
181
  #   single_forwardable.def_delegator :@records, :<<
 
182
  #   single_forwardable.def_delegator :@records, :map
 
183
  #
 
184
  # See the example at forwardable.rb.
 
185
  #
 
186
  def def_singleton_delegators(accessor, *methods)
 
187
    for method in methods
 
188
      def_singleton_delegator(accessor, method)
 
189
    end
 
190
  end
 
191
 
 
192
  #
 
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.
 
196
  #
 
197
  # See the example at forwardable.rb.
 
198
  #
 
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)
 
203
 
 
204
    instance_eval(<<-EOS, "(__FORWARDABLE__)", 1)
 
205
       def #{ali}(*args, &block)
 
206
         begin
 
207
           #{accessor}.__send__(:#{method}, *args,&block)
 
208
         rescue Exception
 
209
           $@.delete_if{|s| /^\\(__FORWARDABLE__\\):/ =~ s} unless Forwardable::debug
 
210
           Kernel::raise
 
211
         end
 
212
       end
 
213
    EOS
 
214
  end
 
215
 
 
216
  alias def_delegators def_singleton_delegators
 
217
  alias def_delegator def_singleton_delegator
 
218
end