From: James Edward Gray II Date: 2005-09-23T01:54:03+09:00 Subject: Re: Delegate and Forwardable Documentation --Apple-Mail-14-924450313 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=US-ASCII; delsp=yes; format=flowed On Sep 22, 2005, at 9:02 AM, James Edward Gray II wrote: > These files are documented copies of the Delegate and Forwardable > libraries that Gavin Sinclair and I wrote back in December. > > > > Looks like delegate changed quite a bit between December and now. Here's updated documentation, in diff form this time. Can this be applied? James Edward Gray II --Apple-Mail-14-924450313 Content-Transfer-Encoding: 7bit Content-Type: application/octet-stream; x-unix-mode=0644; name="forwardable_and_delegate_docs.diff" Content-Disposition: attachment; filename=forwardable_and_delegate_docs.diff Index: lib/.document =================================================================== RCS file: /src/ruby/lib/.document,v retrieving revision 1.8 diff -r1.8 .document 16a17,18 > delegate.rb > erb.rb 18a21 > forwardable.rb Index: lib/delegate.rb =================================================================== RCS file: /src/ruby/lib/delegate.rb,v retrieving revision 1.28 diff -r1.28 delegate.rb 1,17c1,110 < # Delegation class that delegates even methods defined in super class, < # which can not be covered with normal method_missing hack. < # < # Delegator is the abstract delegation class. Need to redefine < # `__getobj__' method in the subclass. SimpleDelegator is the < # concrete subclass for simple delegation. < # < # Usage: < # foo = Object.new < # foo2 = SimpleDelegator.new(foo) < # foo.hash == foo2.hash # => false < # < # Foo = DelegateClass(Array) < # < # class ExtArray # = delegate -- Support for the Delegation Pattern > # > # Documentation by James Edward Gray II and Gavin Sinclair > # > # == Introduction > # > # This library provides three different ways to delegate method calls to an > # object. The easiest to use is SimpleDelegator. Pass an object to the > # constructor and all methods supported by the object will be delegated. This > # object can be changed later. > # > # Going a step further, the top level DelegateClass method allows you to easily > # setup delegation through class inheritance. This is considerably more > # flexible and thus probably the most common use for this library. > # > # Finally, if you need full control over the delegation scheme, you can inherit > # from the abstract class Delegator and customize as needed. (If you find > # yourself needing this control, have a look at _forwardable_, also in the > # standard library. It may suit your needs better.) > # > # == Notes > # > # Be advised, RDoc will not detect delegated methods. > # > # delegate.rb provides full-class delegation via the > # DelegateClass() method. For single-method delegation via > # def_delegator(), see forwardable.rb. > # > # == Examples > # > # === SimpleDelegator > # > # Here's a simple example that takes advantage of the fact that > # SimpleDelegator's delegation object can be changed at any time. > # > # class Stats > # def initialize > # @source = SimpleDelegator.new([]) > # end > # > # def stats( records ) > # @source.__setobj__(records) > # > # "Elements: #{@source.size}\n" + > # " Non-Nil: #{@source.compact.size}\n" + > # " Unique: #{@source.uniq.size}\n" > # end > # end > # > # s = Stats.new > # puts s.stats(%w{James Edward Gray II}) > # puts > # puts s.stats([1, 2, 3, nil, 4, 5, 1, 2]) > # > # Prints: > # > # Elements: 4 > # Non-Nil: 4 > # Unique: 4 > # > # Elements: 8 > # Non-Nil: 7 > # Unique: 6 > # > # === DelegateClass() > # > # Here's a sample of use from tempfile.rb. > # > # A _Tempfile_ object is really just a _File_ object with a few special rules > # about storage location and/or when the File should be deleted. That makes for > # an almost textbook perfect example of how to use delegation. > # > # class Tempfile < DelegateClass(File) > # # constant and class member data initialization... > # > # def initialize(basename, tmpdir=Dir::tmpdir) > # # build up file path/name in var tmpname... > # > # @tmpfile = File.open(tmpname, File::RDWR|File::CREAT|File::EXCL, 0600) > # > # # ... > # > # super(@tmpfile) > # > # # below this point, all methods of File are supported... > # end > # > # # ... > # end > # > # === Delegator > # > # SimpleDelegator's implementation serves as a nice example here. > # > # class SimpleDelegator < Delegator > # def initialize(obj) > # super # pass obj to Delegator constructor, required > # @_sd_obj = obj # store obj for future use > # end > # > # def __getobj__ > # @_sd_obj # return object we are delegating to, required > # end > # > # def __setobj__(obj) > # @_sd_obj = obj # change delegation object, a feature we're providing > # end > # > # # ... > # end 18a112,116 > # > # Delegator is an abstract class used to build delegator pattern objects from > # subclasses. Subclasses should redefine \_\_getobj\_\_. For a concrete > # implementation, see SimpleDelegator. > # 25a124,127 > # > # Pass in the _obj_ to delegate method calls to. All methods supported by > # _obj_ will be delegated to. > # 29a132 > # Handles the magic of delegation through \_\_getobj\_\_. 42a146,149 > # > # Checks for a method provided by this the delegate object by fowarding the > # call through \_\_getobj\_\_. > # 47a155,158 > # > # This method must be overridden by subclasses and should return the object > # method calls are being delegated to. > # 51a163,166 > # > # This method must be overridden by subclasses and change the object delegate > # to _obj_. > # 55a171 > # Serialization support for the object returned by \_\_getobj\_\_. 58a175 > # Reinitializes delegation from a serialized object. 63a181,186 > # > # A concrete implementation of Delegator, this class provides the means to > # delegate all supported method calls to the object passed into the constructor > # and even to change the object being delegated to at a later time with > # \_\_setobj\_\_ . > # 64a188 > # Returns the current object method calls are being delegated to. 68a193,206 > # > # Changes the delegate object to _obj_. > # > # It's important to note that this does *not* cause SimpleDelegator's methods > # to change. Because of this, you probably only want to change delegation > # to objects of the same type as the original delegate. > # > # Here's an example of changing the delegation object. > # > # names = SimpleDelegator.new(%w{James Edward Gray II}) > # puts names[1] # => Edward > # names.__setobj__(%w{Gavin Sinclair}) > # puts names[1] # => Sinclair > # 73a212 > # Clone support for the object returned by \_\_getobj\_\_. 78a218 > # Duplication support for the object returned by \_\_getobj\_\_. 85a226 > # :stopdoc: 88a230 > # :startdoc: 90a233,241 > # The primary interface to this library. Use to setup delegation when defining > # your class. > # > # class MyClass < DelegateClass( ClassToDelegateTo ) # Step 1 > # def initiaize > # super(obj_of_ClassToDelegateTo) # Step 2 > # end > # end > # 100c251 < def initialize(obj) --- > def initialize(obj) # :nodoc: 103c254 < def method_missing(m, *args) --- > def method_missing(m, *args) # :nodoc: 109c260 < def respond_to?(m) --- > def respond_to?(m) # :nodoc: 113c264 < def __getobj__ --- > def __getobj__ # :nodoc: 116c267 < def __setobj__(obj) --- > def __setobj__(obj) # :nodoc: 120c271 < def clone --- > def clone # :nodoc: 124c275 < def dup --- > def dup # :nodoc: 147a299,300 > # :enddoc: > Index: lib/forwardable.rb =================================================================== RCS file: /src/ruby/lib/forwardable.rb,v retrieving revision 1.2 diff -r1.2 forwardable.rb 0a1 > # = forwardable - Support for the Delegation Pattern 2,9c3,6 < # forwardable.rb - < # $Release Version: 1.1$ < # $Revision: 1.2 $ < # $Date: 2001/11/03 13:41:57 $ < # by Keiju ISHITSUKA(keiju@ishitsuka.com) < # original definition by delegator.rb < # -- < # Usage: --- > # $Release Version: 1.1$ > # $Revision: 1.2 $ > # $Date: 2001/11/03 13:41:57 $ > # by Keiju ISHITSUKA(keiju@ishitsuka.com) 11c8,34 < # class Foo --- > # Documentation by James Edward Gray II and Gavin Sinclair > # > # == Introduction > # > # This library allows you delegate method calls to an object, on a method by > # method basis. You can use Forwardable to setup this delegation at the class > # level, or SingleForwardable to handle it at the object level. > # > # == 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. > # > # == Examples > # > # === Forwardable > # > # Forwardable makes building a new class based on existing work, with a proper > # interface, almost trivial. We want to rely on what has come before obviously, > # but with delegation we can take just the methods we need and even rename them > # as appropriate. In many cases this is preferable to inheritance, which gives > # us the entire old interface, even if much of it isn't needed. > # > # class Queue 12a36,100 > # > # def initialize > # @q = [ ] # prepare delegate object > # end > # > # # setup prefered 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 = 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 > # > # Prints: > # > # 2 > # 3 > # 4 > # 5 > # 6 > # Ruby > # nil > # > # === SingleForwardable > # > # printer = String.new > # printer.extend SingleForwardable # prepare object for delegation > # printer.def_delegator "STDOUT", "puts" # add delegation for STDOUT.puts() > # printer.puts "Howdy!" > # > # Prints: > # > # Howdy! > > # > # 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: > # > # class RecordCollection > # extends Forwardable > # def_delegator :@records, :[], :record_number > # end > # > # Further, if you wish to provide the methods #size, #<<, and #map, > # all of which delegate to @records, this is how you can do it: 14,16c102,104 < # def_delegators("@out", "printf", "print") < # def_delegators(:@in, :gets) < # def_delegator(:@contents, :[], "content_at") --- > # class RecordCollection > # # extends Forwardable, but we did that above > # def_delegators :@records, :size, :<<, :map 18,26d105 < # f = Foo.new < # f.printf ... < # f.gets < # f.content_at(1) < # < # g = Goo.new < # g.extend SingleForwardable < # g.def_delegator("@out", :puts) < # g.puts ... 27a107 > # Also see the example at forwardable.rb. 29d108 < 33a113 > # force Forwardable to show up in stack backtraces of delegated methods 36a117,129 > # > # 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 > # > # See the examples at Forwardable and forwardable.rb. > # 42a136,142 > # > # Defines a method _method_ which delegates to _obj_ (i.e. it calls > # the method of the same name in _obj_). If _new_name_ is > # provided, it is used as the name for the delegate method. > # > # See the examples at Forwardable and forwardable.rb. > # 63a164,171 > # > # The SingleForwardable module provides delegation of specified > # methods to a designated object, using the methods #def_delegator > # and #def_delegators. This module is similar to Forwardable, but it works on > # objects themselves, instead of their defining classes. > # > # Also see the example at forwardable.rb. > # 64a173,185 > # > # Shortcut for defining multiple delegator methods, but with no > # provision for using a different name. The following two code > # samples have the same effect: > # > # single_forwardable.def_delegators :@records, :size, :<<, :map > # > # single_forwardable.def_delegator :@records, :size > # single_forwardable.def_delegator :@records, :<< > # single_forwardable.def_delegator :@records, :map > # > # See the example at forwardable.rb. > # 70a192,198 > # > # Defines a method _method_ which delegates to _obj_ (i.e. it calls > # the method of the same name in _obj_). If _new_name_ is > # provided, it is used as the name for the delegate method. > # > # See the example at forwardable.rb. > # --Apple-Mail-14-924450313 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=US-ASCII; format=flowed --Apple-Mail-14-924450313--