module Forwarding
  # Forwarding class in the ruby book p.370
  # plus an extention by Horinouchi 2000/01/31
  #
  # def_forwarding!   same as def_delegate (or def_delegator) in the book.
  #                   Reflects a method to an instance variable,
  #                   which is potentially destructive (if the method is so)
  # def_forwarding    same but duplicates the instance first (by Horinouchi)
  # def_forwardings!  bulk def_forwarding!
  # def_forwardings   bulk def_forwarding

  def def_forwardings!(accessor, *methods)
    for method in methods
      def_forwarding!(accessor, method)
    end
  end

  def def_forwardings(accessor, *methods)
    for method in methods
      def_forwarding(accessor, method)
    end
  end

  def def_forwarding!(accessor, method, ali=method)
    accessor = accessor.id2name if accessor.kind_of?(Integer)
    method = method.id2name if method.kind_of?(Integer)
    ali = ali.id2name if ali.kind_of?(Integer)
    module_eval "def #{ali}(*args,&block); #{accessor}.__send__(:#{method}, *args, &block); end"
  end

  def def_forwarding(accessor, method, ali=method)
    accessor = accessor.id2name if accessor.kind_of?(Integer)
    method = method.id2name if method.kind_of?(Integer)
    ali = ali.id2name if ali.kind_of?(Integer)
    module_eval "def #{ali}(*args,&block);r=self.dup;a=#{accessor}.__send__(:#{method}, *args, &block); r.instance_eval{#{accessor}=a.dup};r;end"
  end

end

if __FILE__ == $0
  require 'basicnumarray'
  class NumArray ##< SimpleDelegator
    extend Forwarding
    def initialize(*shape)
      @shape=shape.dup            # lengths of dimensions
      @nd=@shape.length      #   # of dimension
      @ntot=1 ; for i in 0..@nd-1 ; @ntot*=@shape[i]; end
      @data=BasicNumArray.new(@ntot)
      ##super(@data)
    end

    def_forwardings! :@data, :span, :product
    def_forwardings :@data, :sin
  end

  a=NumArray.new(4,3)
  a.span(1)
  p a,a.product
  p a.sin
end

