Module: Forwardable (Ruby 2.2.2)
Description: Module : Forwardable - Ruby 2.2.2

- Home
- Core 2.2.2
- Std-lib 2.2.2
- Downloads

Support for the Ruby 2.2 series has ended. See here for reference.

### Home Classes Methods

### In Files

- forwardable.rb

### Methods

- #def_delegator
- #def_delegators
- #def_instance_delegator
- #def_instance_delegators
- #delegate
- #instance_delegate

### Class/Module Index

Quicksearch

- Forwardable
- SingleForwardable

No matching classes.

# Forwardable

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:

    require 'forwardable'

    class RecordCollection
      attr_accessor :records
      extend Forwardable
      def_delegator :@records, :[], :record_number
    end

We can use the lookup method like so:

    r = RecordCollection.new
    r.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:

    class RecordCollection # re-open RecordCollection class
      def_delegators :@records, :size, :<<, :map
    end

    r = RecordCollection.new
    r.records = [1,2,3]
    r.record_number(0)   # => 1
    r.size               # => 3
    r << 4               # => [1, 2, 3, 4]
    r.map { |x| x * 2 }  # => [2, 4, 6, 8]

You can even extend regular objects with Forwardable.

    my_hash = Hash.new
    my_hash.extend Forwardable              # prepare object for delegation
    my_hash.def_delegator "STDOUT", "puts"  # add delegation for STDOUT.puts()
    my_hash.puts "Howdy!"

## Another example¶ ↑

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
      extend Forwardable

      def initialize
        @q = [ ]    # prepare delegate object
      end

      # setup preferred 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

This should output:

    2
    3
    4
    5
    6
    Ruby
    nil

## 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`.

### Constants

FILE_REGEXP
FORWARDABLE_VERSION

  Version of `forwardable.rb`

### Attributes

debug[RW]

If true, `__FILE__` will remain in the backtrace in the event an Exception is raised.

### Public Instance Methods

def_delegator(accessor, method, ali = method) click to toggle source
Alias for: def_instance_delegator
def_delegators(accessor, *methods) click to toggle source
Alias for: def_instance_delegators
def_instance_delegator(accessor, method, ali = method) click to toggle source

Define `method` as delegator instance method with an optional alias name `ali`. Method calls to `ali` will be delegated to `accessor.method`.

    class MyQueue
      extend Forwardable
      attr_reader :queue
      def initialize
        @queue = []
      end

      def_delegator :@queue, :push, :mypush
    end

    q = MyQueue.new
    q.mypush 42
    q.queue    #=> [42]
    q.push 23  #=> NoMethodError

                   # File forwardable.rb, line 179
    def def_instance_delegator(accessor, method, ali = method)
      line_no = __LINE__; str = %{
        def #{ali}(*args, &block)
          begin
            #{accessor}.__send__(:#{method}, *args, &block)
          rescue Exception
            $@.delete_if{|s| Forwardable::FILE_REGEXP =~ s} unless Forwardable::debug
            ::Kernel::raise
          end
        end
      }
      # If it's not a class or module, it's an instance
      begin
        module_eval(str, __FILE__, line_no)
      rescue
        instance_eval(str, __FILE__, line_no)
      end

    end

Also aliased as: def_delegator
def_instance_delegators(accessor, *methods) click to toggle source

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

                   # File forwardable.rb, line 152
    def def_instance_delegators(accessor, *methods)
      methods.delete("__send__")
      methods.delete("__id__")
      for method in methods
        def_instance_delegator(accessor, method)
      end
    end

Also aliased as: def_delegators
delegate(hash) click to toggle source
Alias for: instance_delegate
delegate method => accessor click to toggle source
delegate [method, method, ...] => accessor

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.

                   # File forwardable.rb, line 132
    def instance_delegate(hash)
      hash.each{ |methods, accessor|
        methods = [methods] unless methods.respond_to?(:each)
        methods.each{ |method|
          def_instance_delegator(accessor, method)
        }
      }
    end

Also aliased as: delegate