/**
 * Varargs-like demo combining Function#argumentNames and
 * Function#wrap as a demo exercice for The Bungee Book's
 * blog (http://thebungeebook.net/).
 *
 * © 2008 Christophe Porteneuve <tdd@tddsworld.com>
 * Free for all uses.
 */

Object.enableVarArgs = function(object) {
  for (var methodName in object) {
    var method = object[methodName];
    if (!Object.isFunction(method)) continue;
    (function() {
      var argNames = method.argumentNames();
      if (argNames.last() != 'anythingElse') return;
      object[methodName] = method.wrap(function() {
        var args = $A(arguments), proceed = args.shift();
        args[argNames.length - 1] = args.slice(argNames.length - 1);
        args.length = argNames.length;
        return proceed.apply(this, args);
      });
    })();
  }
};

Class.enableVarArgs = function(klass) {
  return Object.enableVarArgs(klass.prototype);
};

var obj = {
  method1: function(a, b) {
    console.log("CALLED: method1(" +
      Object.inspect(a) + ', ' +
      Object.inspect(b) + ")");
  },
  
  someMethod: function(a, b, anythingElse) {
    console.log("CALLED: someMethod(" +
      Object.inspect(a) + ", " + Object.inspect(b) + ", " +
      Object.inspect(anythingElse) + ")");
  },
  
  method2: function(anythingElse) {
    console.log("CALLED: method2(" +
      Object.inspect(anythingElse) + ")");
  }
};

var Klass = Class.create(obj);
var obj2 = new Klass();

Class.enableVarArgs(Klass);
Object.enableVarArgs(obj);

obj.method1(1, 2, 3, 4);
obj.someMethod(1, 2, 3, 4);
obj.method2(1, 2, 3, 4);
obj2.method1(1, 2, 3, 4);
obj2.someMethod(1, 2, 3, 4);
obj2.method2(1, 2, 3, 4);