863 lines
22 KiB
JavaScript
863 lines
22 KiB
JavaScript
/*
|
|
beyond.js
|
|
by Dan Shappir and Sjoerd Visscher
|
|
For more information see http://w3future.com/html/beyondJS
|
|
*/
|
|
var beyondVer = 1.00;
|
|
|
|
var _FP = Function.prototype;
|
|
if ( typeof(parseInt.apply) != "function" ) {
|
|
_FP.apply = function(obj, args) {
|
|
var s, tmp;
|
|
if ( obj ) {
|
|
tmp = "__tmp__"; // + Math.random();
|
|
switch ( typeof(obj) ) {
|
|
case "string":
|
|
s = "'" + obj.replace(_FP.apply.re, "\\'") + "'";
|
|
_SP[tmp] = this;
|
|
break;
|
|
case "number":
|
|
s = "(" + obj + ")";
|
|
_NP[tmp] = this;
|
|
break;
|
|
default:
|
|
s = "obj";
|
|
obj[tmp] = this;
|
|
break;
|
|
}
|
|
s = "var r = " + s + "." + tmp + "(";
|
|
}
|
|
else
|
|
s = "var r = this(";
|
|
for ( var i = 0 ; i < args.length ; ++i )
|
|
s += "args[" + i + "],";
|
|
s = ( args.length ? s.slice(0, -1) : s ) + ");";
|
|
eval(s);
|
|
return r;
|
|
};
|
|
_FP.apply.re = /\'/g;
|
|
_FP.call = function(obj) {
|
|
return this.apply(obj, Array.from(arguments).slice(1));
|
|
};
|
|
}
|
|
|
|
function isUndefined(x) {
|
|
var t = typeof(x);
|
|
return t == "undefined" || t == "unknown";
|
|
}
|
|
function isDefined(x) {
|
|
return !isUndefined(x);
|
|
}
|
|
|
|
Object.propertyNames = function(x, a) {
|
|
if ( !a ) a = [];
|
|
for ( var i in x )
|
|
a.append(i);
|
|
return a;
|
|
};
|
|
Object.propertyValues = function(x, a) {
|
|
return Object.propertyNames(x).collect(a, Function.from(x, null));
|
|
};
|
|
Object.toArray = function(x) {
|
|
return Object.propertyNames(x).zip(Object.propertyValues(x));
|
|
};
|
|
Object.from = function(n, v, x) {
|
|
if ( !x ) x = {};
|
|
var length = Math.min(n.length, v.length);
|
|
for ( var i = 0 ; i < length ; ++i )
|
|
x[n[i]] = v[i];
|
|
return x;
|
|
};
|
|
|
|
_FP.force = function() {
|
|
return "returnValue" in this ? this.returnValue : this.returnValue = this.call();
|
|
};
|
|
_FP.delayed = function() {
|
|
return Function.from(this.curry(arguments), "force");
|
|
};
|
|
_FP.caching = function() {
|
|
var self = this;
|
|
var map = {};
|
|
return function() {
|
|
var s = Array.from(arguments).toString();
|
|
return isDefined(map[s]) ? map[s] : map[s] = self.apply(this, arguments);
|
|
}.withArgString(this);
|
|
};
|
|
|
|
_FP.withArgString = function(x) {
|
|
if ( !x ) return this;
|
|
if ( typeof(x) != "string" )
|
|
x = Function.argString(x);
|
|
var self = this;
|
|
eval("function __withArgString__(" + x + ") { return self.apply(this, arguments); }");
|
|
return __withArgString__;
|
|
};
|
|
_FP.curry = function(m) {
|
|
var self = this;
|
|
var map = arguments.length != 1 || !m || typeof(m) != "object" ? arguments : m;
|
|
function createApplyArg(x) {
|
|
var val = map[x];
|
|
if ( val && val.asArgNameFlag ) {
|
|
args.append(val.toString());
|
|
return val.toString();
|
|
}
|
|
var arg = "__curry__.map['" + x + "']";
|
|
if ( typeof(val) == "function" && val.asValueFlag ) {
|
|
var list = addArgs(val);
|
|
if ( list.length ) list = "," + list;
|
|
arg += ".call(this" + list + ")";
|
|
}
|
|
return arg;
|
|
}
|
|
function addArgs(f) {
|
|
var args = Function.argString(f);
|
|
if ( !args )
|
|
return "";
|
|
args.split(_FP.curry.re).foreach(function(arg) {
|
|
if ( argSet.addToSet(arg) )
|
|
extraArgs.append(arg);
|
|
});
|
|
return args;
|
|
}
|
|
var origargs = Function.argString(this);
|
|
origargs = origargs ? origargs.split(_FP.curry.re) : [];
|
|
if ( map !== m && origargs.length < arguments.length ) origargs.length = arguments.length;
|
|
var args = [], extraArgs = [], argSet = new stringSet;
|
|
var applyArgs = origargs.collect(function(a, i) {
|
|
if ( isUndefined(a) ) {
|
|
if ( isDefined(map[i]) )
|
|
return createApplyArg(i);
|
|
a = "arg" + i;
|
|
args.append(a);
|
|
return a;
|
|
}
|
|
if ( isDefined(map[a]) )
|
|
return createApplyArg(a);
|
|
if ( isDefined(map[i]) )
|
|
return createApplyArg(i);
|
|
if ( isDefined(map[i - self.length]) )
|
|
return createApplyArg(i - self.length);
|
|
args.append(a);
|
|
return a;
|
|
});
|
|
eval("function __curry__(" + args.concat(extraArgs).join(",") + ") {" +
|
|
"return self.apply(this, " +
|
|
(applyArgs.length == 1 ? "[].append(" + applyArgs[0] + ")" : "[" + applyArgs.join(",") + "]") +
|
|
"); }");
|
|
__curry__.map = map;
|
|
return __curry__;
|
|
};
|
|
_FP.curry.re = /\s*,\s*/;
|
|
_FP.using = function() {
|
|
return this.curry(Array.from(arguments).collect(select.curry("typeof", {
|
|
"function" : function(x) { return x.asValue(); },
|
|
"string" : function(x) { return x.asArgName(); },
|
|
"undefined" : function(x) { return x; }
|
|
})));
|
|
};
|
|
|
|
_FP.andThen = function(f) {
|
|
eval("function first(" + Function.argString(this) + ") { return g.first.apply(this, arguments); }");
|
|
function second(x) {
|
|
return g.second.apply ? g.second.apply(this, arguments) : g.second(x);
|
|
}
|
|
var g = second.using(first);
|
|
g.first = this;
|
|
g.second = typeof(f) != "string" ? f : Function.from(null, f);
|
|
return g;
|
|
};
|
|
_FP.andReturn = function(v) {
|
|
return this.andThen(Function.from(v));
|
|
};
|
|
_FP.replace = function(orig, replace) {
|
|
if ( !replace )
|
|
replace = Function.NOP;
|
|
if ( this.second == orig )
|
|
this.second = replace;
|
|
else for ( var f = this ; f.second ; f = f.second )
|
|
if ( f.first == orig )
|
|
f.first = replace;
|
|
return this;
|
|
};
|
|
|
|
_FP.strict = function(args) {
|
|
var self = this, type = typeof(args), length;
|
|
if ( type == "number" )
|
|
length = args;
|
|
if ( type != "string" )
|
|
args = Function.argString(this);
|
|
if ( type != "number" )
|
|
length = args.split(",").length;
|
|
return function() {
|
|
return self.apply(this, Array.from(arguments).head(length));
|
|
}.withArgString(args);
|
|
};
|
|
|
|
_FP.delay = function(iMilliSeconds) {
|
|
var self = this;
|
|
if ( !iMilliSeconds )
|
|
iMilliSeconds = 0;
|
|
return function() {
|
|
var args = arguments;
|
|
return window.setTimeout(function() { self.apply(this, args); }, iMilliSeconds);
|
|
}.withArgString(this);
|
|
};
|
|
_FP.asValue = function() {
|
|
var f = this.curry({});
|
|
f.asValueFlag = true;
|
|
return f;
|
|
};
|
|
_FP.toMethod = function() {
|
|
return this.using(Function.This);
|
|
};
|
|
_FP.gate = function(cond, els) {
|
|
var gate = function() {
|
|
return ( typeof(gate.cond) == "function" ? gate.cond.apply(this, arguments) : gate.cond ) ?
|
|
gate.then.apply(this, arguments) :
|
|
typeof(gate.els) == "function" ? gate.els.apply(this, arguments) : gate.els;
|
|
}.withArgString(this);
|
|
gate.cond = cond;
|
|
gate.then = this;
|
|
gate.els = els;
|
|
return gate;
|
|
};
|
|
_FP.loop = function(cond) {
|
|
var loop = function() {
|
|
while ( select("typeof", {
|
|
"function" : function(x) { return x.apply(this, arguments); },
|
|
"number" : function() { return loop.cond--; },
|
|
"undefined" : isDefined(loop.cond) ? loop.cond : true
|
|
}, loop.cond) ) {
|
|
var r = loop.action.apply(this, arguments);
|
|
if ( isDefined(r) )
|
|
return r;
|
|
}
|
|
}.withArgString(this);
|
|
loop.cond = cond;
|
|
loop.action = this;
|
|
return loop;
|
|
};
|
|
|
|
_FP.factory = function() {
|
|
var self = this;
|
|
return function() {
|
|
return eval("new self(" +
|
|
(0).upTo(arguments.length-1).join2("arguments[", ",", "]") +
|
|
")");
|
|
}.withArgString(this);
|
|
};
|
|
|
|
Function.argString = function(f) {
|
|
var result = ("" + f).match(Function.argString.re);
|
|
return result ? result[1] : null;
|
|
};
|
|
Function.argString.re = /\(([^)]*)/;
|
|
Function.NOP = function() {
|
|
if ( arguments.length > 0 )
|
|
return arguments[0];
|
|
};
|
|
Function.This = function() {
|
|
return this;
|
|
};
|
|
Function.args = function() {
|
|
return Array.from(arguments);
|
|
};
|
|
Function.invoke = function(f) {
|
|
return f();
|
|
};
|
|
Function.event = function(e) {
|
|
return e ? e : event;
|
|
};
|
|
|
|
Function.from = function(obj, field, args) {
|
|
var f;
|
|
if ( isUndefined(obj) || obj === null ) {
|
|
f = function(obj) {
|
|
return Function.from(obj, f.field, args).apply(obj, Array.from(arguments).slice(1));
|
|
};
|
|
if ( args && args.length )
|
|
f = f.withArgString("obj," + args);
|
|
}
|
|
else if ( isUndefined(field) ) {
|
|
if ( !args )
|
|
args = Function.argString(obj);
|
|
if ( typeof(args) != "string" )
|
|
f = function() {
|
|
return f.obj;
|
|
};
|
|
else
|
|
f = function() {
|
|
return f.obj.apply(this, arguments);
|
|
}.withArgString(args);
|
|
}
|
|
else if ( field === null )
|
|
f = function(x) {
|
|
return f.obj[x];
|
|
};
|
|
else if ( typeof(field) == "function" )
|
|
f = function() {
|
|
return f.field.apply(f.obj, arguments);
|
|
}.withArgString(args ? args : Function.argString(field));
|
|
else {
|
|
if ( !args )
|
|
args = Function.argString(obj[field]);
|
|
if ( typeof(args) != "string" )
|
|
f = function() {
|
|
if ( f.field.search(/\s/) > -1 )
|
|
return f.obj[f.field];
|
|
return eval("f.obj." + f.field);
|
|
};
|
|
else
|
|
f = function() {
|
|
if ( f.field.search(/\s/) > -1 )
|
|
return f.obj[f.field].apply(f.obj, arguments);
|
|
var s = "f.obj." + f.field + "(";
|
|
Array.from(arguments).foreach(function(v, i) { s += "arguments[" + i + "],"; });
|
|
return eval(( arguments.length ? s.slice(0, -1) : s ) + ");");
|
|
}.withArgString(args);
|
|
}
|
|
f.obj = obj;
|
|
f.field = field;
|
|
return f;
|
|
}
|
|
Function.set = function(obj, property) {
|
|
var f;
|
|
if ( isUndefined(obj) || obj === null )
|
|
f = function(obj, value) {
|
|
return Function.set(obj, f.property).call(this, value);
|
|
};
|
|
else if ( isUndefined(property) )
|
|
f = function(property, value) {
|
|
return Function.set(f.obj, property).call(this, value);
|
|
};
|
|
else
|
|
f = function(value) {
|
|
if ( f.property.search(/\s/) > -1 )
|
|
f.obj[f.property] = value;
|
|
else
|
|
eval("f.obj." + f.property + " = value");
|
|
return value;
|
|
}
|
|
f.obj = obj;
|
|
f.property = property;
|
|
return f;
|
|
}
|
|
|
|
var _AP = Array.prototype;
|
|
if ( typeof(_AP.push) != "function" )
|
|
_AP.push = function() {
|
|
for ( var i = 0 ; i < arguments.length ; ++i )
|
|
this[this.length] = arguments[i];
|
|
return this.length;
|
|
}
|
|
if ( typeof(_AP.pop) != "function" )
|
|
_AP.pop = function() {
|
|
if ( this.length ) {
|
|
var item = this[this.length-1];
|
|
--this.length;
|
|
return item;
|
|
}
|
|
}
|
|
if ( typeof(_AP.shift) != "function" )
|
|
_AP.shift = function() {
|
|
this.foreach(function(v, i, self) { self[i] = self[i+1]; });
|
|
--this.length;
|
|
return this;
|
|
}
|
|
if ( typeof(_AP.unshift) != "function" )
|
|
_AP.unshift = function() {
|
|
var self = this;
|
|
Array.from(arguments).concat(this).foreach(function(v, i) { self[i] = v; });
|
|
return this;
|
|
}
|
|
if ( typeof(_AP.splice) != "function" )
|
|
_AP.splice = function(start, deleteCount) {
|
|
var a = start > 0 ? this.slice(0, start) : [];
|
|
a = a.concat(Array.from(arguments).slice(2), this.slice(start+deleteCount));
|
|
var self = this, deleted = this.slice(start, start+deleteCount);
|
|
a.foreach(function(v, i) { self[i] = v; });
|
|
this.length = a.length;
|
|
return deleted;
|
|
}
|
|
|
|
_AP.head = function(length) {
|
|
return isUndefined(length) ? this[0] : this.slice(0, length);
|
|
};
|
|
_AP.tail = function(start) {
|
|
return this.slice(start ? start : 1);
|
|
};
|
|
_AP.itemAt = function(i) {
|
|
return this[i];
|
|
};
|
|
_AP.isEmpty = function() {
|
|
return this.length === 0;
|
|
};
|
|
_AP.empty = function() {
|
|
this.length = 0;
|
|
return this;
|
|
};
|
|
|
|
_AP.order = function(f) {
|
|
if ( !f )
|
|
f = function(a, b) {
|
|
return a < b ? -1 : a > b ? 1 : 0;
|
|
};
|
|
return this.sort(function(a, b) {
|
|
var r = 0;
|
|
a.zip(b).foreach(function(pair) {
|
|
if ( r = f(pair[0], pair[1]) )
|
|
return false;
|
|
});
|
|
return r;
|
|
});
|
|
};
|
|
|
|
_AP.join2 = function(prefix, infix, postfix) {
|
|
if ( isUndefined(prefix) || prefix === null ) prefix = "";
|
|
if ( isUndefined(infix) || infix === null ) infix = "";
|
|
if ( isUndefined(postfix) || postfix === null ) postfix = "";
|
|
var r = this.join(postfix + infix + prefix);
|
|
return r.length ? prefix + r + postfix : r;
|
|
};
|
|
|
|
_AP.append = function() {
|
|
for ( var i = 0 ; i < arguments.length ; ++i )
|
|
if ( isDefined(arguments[i]) )
|
|
this[this.length] = arguments[i];
|
|
return this;
|
|
};
|
|
_AP.extend = function(x) {
|
|
if ( isDefined(x) ) {
|
|
if ( x.constructor == Array || typeof(x.foreach) != "function")
|
|
this.concat(x);
|
|
else {
|
|
var self = this;
|
|
x.foreach(function(v) { self.append(v); });
|
|
}
|
|
}
|
|
return this;
|
|
};
|
|
_AP.feed = function(x) {
|
|
x.extend(this);
|
|
return this;
|
|
};
|
|
|
|
_AP.foreach = function(f) {
|
|
for ( var i = 0 ; i < this.length ; ++i )
|
|
if ( f(this[i], i, this) === false )
|
|
return i;
|
|
};
|
|
_AP.coalesce = function(r, f) {
|
|
if ( isUndefined(f) ) {
|
|
f = arguments[0];
|
|
r = arguments[1];
|
|
}
|
|
if ( typeof(f) == "string" )
|
|
f = f.asMethod();
|
|
this.foreach(function(v, i, self) {
|
|
var t = f(r, v, i, self);
|
|
if ( isDefined(t) )
|
|
r = t;
|
|
});
|
|
return r;
|
|
};
|
|
_AP.fold = function(r, f) {
|
|
if ( isUndefined(f) ) {
|
|
f = arguments[0];
|
|
r = arguments[1];
|
|
}
|
|
if ( typeof(f) == "string" )
|
|
f = f.toFunction();
|
|
return this.coalesce(r, function(r, v) {
|
|
return isDefined(r) ? f(r, v) : v;
|
|
});
|
|
};
|
|
_AP.foldr = function(r, f) {
|
|
if ( isUndefined(f) ) {
|
|
f = arguments[0];
|
|
r = arguments[1];
|
|
}
|
|
if ( typeof(f) == "string" )
|
|
f = f.toFunction();
|
|
return this.fold(r, function(r, v) { return f(v, r); });
|
|
};
|
|
_AP.collect = function(a, f) {
|
|
if ( isUndefined(f) ) {
|
|
f = arguments[0];
|
|
a = arguments[1];
|
|
}
|
|
if ( typeof(f) == "string" )
|
|
f = f.asMethod();
|
|
if ( !a )
|
|
a = this.constructor ? new this.constructor : [];
|
|
return this.coalesce(a, function(r, v, i, self) { return r.append(f(v, i, self)); });
|
|
};
|
|
_AP.call = function(f) {
|
|
this.foreach(f);
|
|
return this;
|
|
};
|
|
|
|
_AP.asLongAs = function(a, f) {
|
|
if ( isUndefined(f) ) {
|
|
f = arguments[0];
|
|
a = arguments[1];
|
|
}
|
|
if ( f.constructor === RegExp )
|
|
f = Function.from(f, "test");
|
|
if ( !a )
|
|
a = this.constructor ? new this.constructor : [];
|
|
this.foreach(function(v, i, self) {
|
|
if ( !f(v, i, self) ) return false;
|
|
a.append(v);
|
|
});
|
|
return a;
|
|
};
|
|
_AP.filter = function(f, other) {
|
|
if ( f.constructor === RegExp )
|
|
f = Function.from(f, "test");
|
|
return this.collect(other ?
|
|
function(v, i, a) {
|
|
if ( f(v, i, a) )
|
|
return v;
|
|
other.append(v);
|
|
} :
|
|
function(v, i, a) {
|
|
if ( f(v, i, a) )
|
|
return v;
|
|
}
|
|
);
|
|
};
|
|
_AP.search = function(f) {
|
|
if ( f.constructor === RegExp )
|
|
f = Function.from(f, "test");
|
|
else if ( typeof(f) != "function" ) {
|
|
var x = f;
|
|
f = function(y) { return y === x; };
|
|
}
|
|
var result = this.foreach(function(v, i, self) { return !f(v, i, self); });
|
|
return typeof(result) == "number" ? result : -1;
|
|
};
|
|
_AP.indexOf = function(pattern) {
|
|
if ( typeof(pattern.foreach) != "function" )
|
|
pattern = [].append(pattern);
|
|
var result = this.foreach(function(v, i, self) {
|
|
return -1 !== pattern.foreach(function(v) {
|
|
return v === self[i++];
|
|
});
|
|
});
|
|
return typeof(result) == "number" ? result : -1;
|
|
};
|
|
|
|
_AP.inverse = function() {
|
|
return this.collect(function(v) {
|
|
return typeof(v.reverse) == "function" ? v.reverse() : v;
|
|
}).reverse();
|
|
}
|
|
|
|
_AP.flush = function(f) {
|
|
for ( ; this.length ; this.shift() )
|
|
if ( f(this[0], this) === false )
|
|
break;
|
|
return this;
|
|
};
|
|
_AP.split = function(f) {
|
|
if ( f.constructor === RegExp )
|
|
f = Function.from(f, "test");
|
|
else if ( typeof(f) != "function" )
|
|
f = "===".curry({ 0 : f });
|
|
var a = [[]], index = 0;
|
|
this.foreach(function(v) {
|
|
if ( f(v) )
|
|
a[++index] = [];
|
|
else
|
|
a[index].append(v);
|
|
});
|
|
return a;
|
|
};
|
|
_AP.zip = function() {
|
|
var result = this.collect(function(v) { return Function.args(v); });
|
|
Array.from(arguments).foreach(function(a) {
|
|
if ( !a || isUndefined(a.foreach) )
|
|
a = Function.args(v);
|
|
var last = 0;
|
|
if ( IsUndefined(a.foreach(function(v, i) {
|
|
var x = result.itemAt(i);
|
|
if ( isUndefined(x) ) return false;
|
|
x.push(v);
|
|
last = i;
|
|
})) ) {
|
|
if ( isDefined(result.length) )
|
|
result.length = last+1;
|
|
else
|
|
result = result.slice(0, last+1);
|
|
}
|
|
});
|
|
return result;
|
|
};
|
|
_AP.zipWith = function(f) {
|
|
if ( typeof(f) == "string" ) f = f.toFunction();
|
|
return this.zip.apply(this, Array.from(arguments).tail()).collect(function(v) {
|
|
return f.apply(null, v);
|
|
});
|
|
};
|
|
|
|
_AP.spread = function() {
|
|
return this.coalesce([], "extend");
|
|
};
|
|
|
|
Array.from = function(x) {
|
|
if ( typeof(x.toArray) == "function" ) {
|
|
x = x.toArray();
|
|
if ( this === Array )
|
|
return x;
|
|
}
|
|
if ( typeof(x.foreach) == "function" ) {
|
|
var a = new this;
|
|
x.foreach(function(v) { a.push(v); });
|
|
return a;
|
|
}
|
|
if ( typeof(x.length) == "number" ) {
|
|
var a = new this;
|
|
if ( typeof(x) != "string" )
|
|
for ( i = 0 ; i < x.length ; ++i )
|
|
a.push(x[i]);
|
|
else
|
|
for ( i = 0 ; i < x.length ; ++i )
|
|
a.push(x.charAt(i));
|
|
return a;
|
|
}
|
|
return (new this).push(x);
|
|
}
|
|
Array.fill = function(f, a) {
|
|
if ( !a ) a = new this;
|
|
var i = a.length;
|
|
if ( !i ) i = 0;
|
|
for ( ; ; ++i ) {
|
|
var v = f(i, a);
|
|
if ( isUndefined(v) )
|
|
return a;
|
|
a.append(v);
|
|
}
|
|
};
|
|
Array.recurse = function(f, resultIfEmpty) {
|
|
if ( isUndefined(resultIfEmpty) ) resultIfEmpty = new this;
|
|
return function(x) {
|
|
return this.isEmpty() ?
|
|
typeof(resultIfEmpty) == "function" ?
|
|
resultIfEmpty(x) : resultIfEmpty :
|
|
f(this.head(), this.tail(), x);
|
|
};
|
|
};
|
|
|
|
_AP.equals = Array.recurse(function(h, t, x) {
|
|
return typeof(x.head) == "function" && typeof(x.tail) == "function" &&
|
|
( typeof(h.equals) == "function" ? h.equals(x.head()) : h == x.head() ) &&
|
|
t.equals(x.tail());
|
|
},
|
|
Function.from(null, "isEmpty")
|
|
);
|
|
|
|
function iteratable(x) {
|
|
var p = x.prototype;
|
|
if ( !p || p == Object )
|
|
p = x;
|
|
else {
|
|
if ( typeof(p.push) == "function" ) {
|
|
if ( !x.from )
|
|
x.from = Array.from;
|
|
}
|
|
if ( typeof(p.append) == "function" ) {
|
|
if ( !x.fill )
|
|
x.fill = Array.fill;
|
|
}
|
|
}
|
|
if ( typeof(p.foreach) == "function" ) {
|
|
if ( !p.coalesce )
|
|
p.coalesce = _AP.coalesce;
|
|
if ( !p.fold )
|
|
p.fold = _AP.fold;
|
|
if ( !p.foldr )
|
|
p.foldr = _AP.foldr;
|
|
if ( !p.collect )
|
|
p.collect = _AP.collect;
|
|
if ( !p.filter )
|
|
p.filter = _AP.filter;
|
|
if ( !p.search )
|
|
p.search = _AP.search;
|
|
}
|
|
}
|
|
|
|
var _NP = Number.prototype;
|
|
_NP.times = function(f, counter) {
|
|
counter = counter || 0;
|
|
for ( var i = 0 ; i < this ; ++i )
|
|
f(counter++);
|
|
};
|
|
_NP.upTo = function(target, step) {
|
|
if ( !step ) step = 1;
|
|
var a = [];
|
|
for ( var i = this.valueOf() ; i <= target ; i += step )
|
|
a.append(i);
|
|
return a;
|
|
};
|
|
_NP.downTo = function(target, step) {
|
|
if ( !step ) step = 1;
|
|
var a = [];
|
|
for ( var i = this.valueOf() ; i >= target ; i -= step )
|
|
a.append(i);
|
|
return a;
|
|
};
|
|
_NP.to = function(target, step) {
|
|
return this < target ? this.upTo(target, step) : this.downTo(target, step);
|
|
};
|
|
_NP.chr = function() {
|
|
return String.fromCharCode(this);
|
|
};
|
|
|
|
var _SP = String.prototype;
|
|
_SP.itemAt = String.charAt;
|
|
_SP.asc = function() {
|
|
return this.charCodeAt(0);
|
|
};
|
|
_SP.to = function(target, step) {
|
|
return this.asc().to(target.toString().asc(), step).collect(Function.from(null, "chr"));
|
|
};
|
|
_SP.toFunctionUnary = function() {
|
|
eval("function __unary__(op) { return " + this + " op; }");
|
|
__unary__.op = this;
|
|
return __unary__;
|
|
};
|
|
_SP.toFunctionBinary = function() {
|
|
eval("function __binary__(op1, op2) { return op1 " + this + " op2; }");
|
|
__binary__.op = this;
|
|
return __binary__;
|
|
};
|
|
_SP.toFunction = function() {
|
|
return ",!,~,++,--,new,delete,typeof,void,".indexOf("," + this + ",") > -1 ?
|
|
this.toFunctionUnary() : this.toFunctionBinary();
|
|
};
|
|
_SP.toMethod = function() {
|
|
return this.toFunction().toMethod();
|
|
};
|
|
_SP.apply = function(obj, args) {
|
|
return this.toFunction().apply(obj, args);
|
|
};
|
|
_SP.call = function(obj) {
|
|
return this.toFunction().apply(obj, Array.from(arguments).slice(1));
|
|
};
|
|
_SP.curry = function() {
|
|
return _FP.curry.apply(this.toFunction(), arguments);
|
|
};
|
|
_SP.using = function() {
|
|
return _FP.using.apply(this.toFunction(), arguments);
|
|
};
|
|
_SP.asArgName = function() {
|
|
var self = this;
|
|
return { toString : function() { return self; }, asArgNameFlag : true };
|
|
};
|
|
|
|
_SP.asMethod = function(args) {
|
|
eval("function __method__(obj) { return obj." + this + ".apply(obj, Array.from(arguments).slice(1)); }");
|
|
return args ? __method__.withArgString("obj," + args) : __method__;
|
|
};
|
|
_SP.asMethodUsing = function() {
|
|
var args = (1).upTo(arguments.length).collect(function(v) { return "arg" + v; }).join(",");
|
|
return _FP.curry.apply(this.asMethod(args), (new Array(1)).concat(Array.from(arguments)));
|
|
};
|
|
|
|
var _RP = RegExp.prototype;
|
|
_RP.iterate = function(s, f) {
|
|
var sre = this.toString(), sep = sre.lastIndexOf("/");
|
|
var re = new RegExp(sre.slice(1, sep), sre.slice(sep+1) + "g");
|
|
for ( var a ; a = re.exec(s) ; )
|
|
if ( f(a, s, re) === false )
|
|
return a;
|
|
return null;
|
|
};
|
|
_RP.not = function() {
|
|
return "!".using(Function.from(this, "test", "str"));
|
|
};
|
|
|
|
if ( typeof(Enumerator) == "function" && typeof(Enumerator.prototype) == "object" ) {
|
|
var _EP = Enumerator.prototype;
|
|
_EP.foreach = function(f) {
|
|
for ( this.moveFirst() ; !this.atEnd() ; this.moveNext() )
|
|
if ( f(this.item(), this) === false )
|
|
return this.item();
|
|
return null;
|
|
};
|
|
iteratable(Enumerator);
|
|
}
|
|
|
|
function select(prep, map, selector) {
|
|
if ( arguments.length < 3 ) {
|
|
selector = map;
|
|
map = prep;
|
|
prep = arguments[2];
|
|
}
|
|
var r;
|
|
switch ( typeof(prep) ) {
|
|
case "string":
|
|
prep = prep.toFunction();
|
|
case "function":
|
|
case "object":
|
|
if ( prep ) {
|
|
r = map[prep(selector, this)];
|
|
break;
|
|
}
|
|
default:
|
|
r = map[selector];
|
|
}
|
|
if ( isUndefined(r) ) r = map[r];
|
|
return typeof(r) == "function" ? r.call(this, selector, prep) : r;
|
|
}
|
|
|
|
function stringSet(initItems) {
|
|
if ( initItems )
|
|
this.addToSet.apply(this, initItems);
|
|
}
|
|
stringSet.prototype = {
|
|
addToSet : function(item) {
|
|
var set = this;
|
|
return Array.from(arguments).coalesce(false, function(r, item) {
|
|
return !set[item] ? set[item] = true : r;
|
|
});
|
|
},
|
|
foreach : function(f) {
|
|
for ( var item in this )
|
|
if ( this[item] !== stringSet.prototype[item] && f(item, this) === false )
|
|
return item;
|
|
return null;
|
|
},
|
|
mergeSet : function(set) {
|
|
return Array.from(this).concat(Array.from(set)).toStringSet();
|
|
},
|
|
include : function() {
|
|
return "&&".using(
|
|
Function.from(this, null),
|
|
Function.from(stringSet.prototype, null).andThen(isUndefined));
|
|
},
|
|
exclude : function() {
|
|
return this.include().andThen("!".toFunctionUnary());
|
|
}
|
|
};
|
|
_AP.toStringSet = function() {
|
|
return new stringSet(this);
|
|
};
|
|
|
|
Math.even = function(n) {
|
|
return n % 2 == 0;
|
|
};
|
|
Math.odd = function(n) {
|
|
return n % 2 != 0;
|
|
};
|
|
|
|
var ff = isUndefined(ff) ? Function.from : ff;
|
|
|
|
function debugAlert(x) {
|
|
if ( debugAlert.on )
|
|
Array.from(arguments).foreach(alert);
|
|
if ( arguments.length > 0 )
|
|
return x;
|
|
}
|
|
debugAlert.on = true;
|