Module: Forwardable
| Relationships & Source Files | |
| Defined in: | lib/forwardable.rb | 
Overview
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
endWe can use the lookup method like so:
r = RecordCollection.new
r.records = [4,5,6]
r.record_number(0)  # => 4Further, 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.firstThis should output:
2
3
4
5
6
Ruby
nilNotes
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.
Constant Summary
- 
    FORWARDABLE_VERSION =
    # File 'lib/forwardable.rb', line 114Version of forwardable.rb"1.1.0"
Class Attribute Summary
- 
    
      .debug  
    
    rw
    ignored. 
Class Method Summary
Instance Method Summary
- 
    
      #def_delegator(accessor, method, ali = method)  
    
    Alias for #def_instance_delegator. 
- 
    
      #def_delegators(accessor, *methods)  
    
    Alias for #def_instance_delegators. 
- 
    
      #def_instance_delegator(accessor, method, ali = method)  
      (also: #def_delegator)
    
    Define methodas delegator instance method with an optional alias nameali.
- 
    
      #def_instance_delegators(accessor, *methods)  
      (also: #def_delegators)
    
    Shortcut for defining multiple delegator methods, but with no provision for using a different name. 
- 
    
      #delegate(hash)  
    
    Alias for #instance_delegate. 
- 
    
      #delegate(method)  ⇒ accessor 
      (also: #delegate)
    
    Takes a hash as its argument. 
Class Attribute Details
.debug (rw)
ignored
# File 'lib/forwardable.rb', line 119
attr_accessor :debug
Class Method Details
._delegator_method(obj, accessor, method, ali)
[ GitHub ]# File 'lib/forwardable.rb', line 188
def self._delegator_method(obj, accessor, method, ali) accessor = accessor.to_s unless Symbol === accessor if Module === obj ? obj.method_defined?(accessor) || obj.private_method_defined?(accessor) : obj.respond_to?(accessor, true) accessor = "#{accessor}()" end line_no = __LINE__+1; str = "#{<<-"begin;"}\n#{<<-"end;"}" begin; proc do def #{ali}(*args, &block) begin #{accessor} end.__send__ :#{method}, *args, &block end end end; RubyVM::InstructionSequence .compile(str, __FILE__, __FILE__, line_no, trace_instruction: false, tailcall_optimization: true) .eval end
Instance Method Details
#def_delegator(accessor, method, ali = method)
Alias for #def_instance_delegator.
# File 'lib/forwardable.rb', line 186
alias def_delegator def_instance_delegator
#def_delegators(accessor, *methods)
Alias for #def_instance_delegators.
# File 'lib/forwardable.rb', line 185
alias def_delegators def_instance_delegators
#def_instance_delegator(accessor, method, ali = method) Also known as: #def_delegator
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 'lib/forwardable.rb', line 177
def def_instance_delegator(accessor, method, ali = method) gen = Forwardable._delegator_method(self, accessor, method, ali) # If it's not a class or module, it's an instance (Module === self ? self : singleton_class).module_eval(&gen) end
#def_instance_delegators(accessor, *methods) Also known as: #def_delegators
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 'lib/forwardable.rb', line 150
def def_instance_delegators(accessor, *methods) methods.delete("__send__") methods.delete("__id__") for method in methods def_instance_delegator(accessor, method) end end
#delegate(hash)
Alias for #instance_delegate.
# File 'lib/forwardable.rb', line 184
alias delegate instance_delegate
    
      #delegate(method)  ⇒ accessor 
      #delegate([method, method, ...]=> accessor)  
    
    Also known as: #delegate
  
accessor 
      #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 'lib/forwardable.rb', line 130
def instance_delegate(hash) hash.each{ |methods, accessor| methods = [methods] unless methods.respond_to?(:each) methods.each{ |method| def_instance_delegator(accessor, method) } } end