Patches: Browse | Submit New | Admin

[#1923] Forwardable, reworked

Date:
2005-05-17 14:50
Priority:
3
Submitted By:
Daniel Berger (djberg96)
Assigned To:
Nobody (None)
Category:
Developer Tools/Libs
State:
Open
Summary:
Forwardable, reworked

Detailed description
The following code is a reworked version of the current Forwardable module.  It eliminates SingleForwardable altogther
and adds the "delegate" method, at the suggestion of Florian Gross.

I didn't provide a unified diff because I wasn't sure what additional documentation folks would want to include at the
top of the file (and because there are so many code and doc changes).

Attached is a corresponding test suite that should probably go under test/forwardable (which would need to be created).

Regards,

Dan

# forwardable.rb
#
# == Synopsis
# Provides a mechanism to allow classes to delegate named method calls
# to other objects.
#
# == Usage
#    class Foo
#       extend Forwardable
#       delegate :length => :@str
#       delegate [:first, :last] => :@arr
#       def initialize
#          @arr = ["foo","bar","baz"]
#          @str = "hello"
#       end
#    end
#
#    f = Foo.new
#    puts f.length # 5, length of @str
#    puts f.first  # "foo", first element of @arr
#    puts f.last   # "baz", last element of @arr
#
# == Author
# Keiju Ishitsuka
#
# Revised by: Daniel J. Berger with suggestions from Florian Gross.
#
module Forwardable
   FORWARDABLE_VERSION = "1.0.0"

   # Takes a hash as its argument.  The key is a symbol or an array of
   # symbols.  These symbols correspond to method names.  The value is
   # the accessor to which the methods will be delegated.
   #
   # :call-seq:
   #    delegate method => accessor
   #    delegate [method, method, ...] => accessor
   #
   def delegate(hash)
      hash.each{ |methods, accessor|
         methods = methods.to_s unless methods.respond_to?(:each)
         methods.each{ |method|
            def_instance_delegator(accessor, method)
         }
      }
   end

   # Delegates +methods+ to the given +accessor+.
   #
   # :call-seq:
   #     def_delegators(accessor, *methods)
   #
   def def_instance_delegators(accessor, *methods)
      methods.delete("__send__")
      methods.delete("__id__")
      methods.each{ |method|
         def_instance_delegator(accessor, method)
      }
   end

   # Delegates a single +method+ to the given +accessor+.
   #
   # :call-seq:
   #     def_delegator(accessor, method, alias=nil)
   #
   # If an alias is provided, the accessor will respond to that alias instead
   # of the original method.
   def def_instance_delegator(accessor, method, ali = method)
      str = %Q{
         def #{ali}(*args, &block)
            #{accessor}.send(:#{method}, *args, &block)
         end
      }

      # If it's not a class or module, it's an instance
      begin
         module_eval(str)
      rescue
         instance_eval(str)
      end
  end

  alias def_delegators def_instance_delegators
  alias def_delegator def_instance_delegator
end

Add A Comment: Notepad

Please login


Followup

No Followups Have Been Posted

Attached Files:

Name Description Download
test_forwardable.rb Test suite for the revised Forwardable module Download

Changes:

Field Old Value Date By
assigned_tozenspider2009-02-18 03:29zenspider
assigned_tonone2007-06-13 06:27zenspider
category_idMisc / Other Standard Library2007-05-30 04:18zenspider
category_idCrypto / Digest / Compression2007-05-30 03:50zenspider
artifact_group_idNone2007-05-30 03:41zenspider
File Added212: test_forwardable.rb2005-05-17 14:50djberg96