Code:
var Format = (function() {
function interpolate(s, o) {
s = s.replace(/\[\[/g, '\0');
for (var x in o)
if (o.hasOwnProperty(x))
s = s.replace(new RegExp('\\[' + x + '\\]', 'g'), o[x]);
return s;
}
return {
interpolate: interpolate
};
})();
var Functions = (function() {
var O = {
lookup: function(a, i) {
return a[i];
},
equals: function(a, b) {
return a === b;
}
};
var F = {
bind: function(obj, fun, args) {
return function() {
if (obj === true)
obj = this;
var f = typeof fun === "string" ? obj[fun] : fun;
return f.apply(obj, Array.prototype.slice.call(args || [])
.concat(Array.prototype.slice.call(arguments)));
};
},
compose: function(/* f1 [, f2 [, ... [, fn]]] */) {
var fs = Array.prototype.slice.call(arguments);
return function() {
var args = Array.prototype.slice.call(arguments);
for (var i = fs.length - 1; i >= 0; --i)
args.unshift(fs[i].apply(this, args));
return args[0];
};
},
reorder: function(f, ord) {
return function() {
var oldargs = Array.prototype.slice.call(arguments);
return f.apply(this, F.map(function(v) { return oldargs[v]; }, ord));
};
},
flip: function(f) {
return F.reorder(f, [1, 0]);
},
curry: function(f, l, a) {
l = (typeof l === "number" ? l : (f.length || 0));
a = a || [];
return function() {
var m = a.concat(Array.prototype.slice.call(arguments));
return m.length < l ? Functional.curry(f, l, m) : f.apply(this, m);
};
},
Operators: O
};
return F;
})();
var Lists = {
map: function(f, a) {
for (var i = a.length - 1, r = []; i >= 0; --i)
r[i] = f(a[i], i);
return r;
},
reduce: function(f, t, a) {
for (var i = 0, n = a.length; i < n; ++i)
t = f(t, a[i]);
return t;
},
filter: function(f, a) {
for (var i = 0, r = [], n = a.length; i < n; ++i)
if (f(a[i], i))
r[r.length] = a[i];
return r;
}
};
var using = (function() {
var extensions = {}, global = this;
function isApplied(extn) {
var e = extn.split('.');
return extensions[e[0]][e[1]] && global[e[0]].prototype[e[1]];
}
function apply(extn) {
var e = extn.split('.');
return global[e[0]].prototype[e[1]] = extensions[e[0]][e[1]];
}
function unapply(extn) {
var e = extn.split('.');
delete global[e[0]].prototype[e[1]];
}
function using() {
var extns = Array.prototype.slice.call(arguments);
return function(fn) {
return function() {
for (var i = extns.length; --i >= 0; )
if (!isApplied(extns[i]))
apply(extns[i]);
else
extns.splice(i, 1);
var r = fn.apply(this, Array.prototype.slice.call(arguments));
for (var i = extns.length; --i >= 0; )
unapply(extns[i]);
return r;
};
};
}
function add(c, o) {
for (var x in o)
if (o.hasOwnProperty(x))
(extensions[c] || (extensions[c] = {}))[x] = o[x];
return o;
}
function get() {
return extensions;
}
using.add = add;
using.get = get;
return using;
})();
var Generic = (function() {
var MATCH_FAIL = {},
MATCH_ANY = {};
function create(fallback) {
var s = function() {
for (var i = 0, args = Array.prototype.slice.call(arguments), r; i < specs.length; ++i)
if ((r = specs[i].match(args)) !== MATCH_FAIL)
return r;
if (s._fallback)
return s._fallback.apply(this, args);
throw new Error("Generic: No methods matched and no fallback provided.");
}, specs = s._specs = [];
s.specialise = specialise;
s.addFallback = addFallback;
if (fallback)
s.addFallback(fallback);
return s;
}
function specialise(patterns, func) {
var s = this._specs;
s[s.length] = new Specialisation(patterns, func, this);
return this;
}
function addFallback(func) {
this._fallback = func;
return this;
}
/**** Begin Specialisation ****/
function Specialisation(patterns, func, context) {
this.patterns = patterns;
this.func = func;
this.context = context;
}
Specialisation.compatible = function(value, pattern) {
if (pattern === MATCH_ANY && value !== undefined)
return true;
else if ((typeof pattern === "string" || pattern instanceof String) && typeof value === pattern)
return true;
else if ((typeof pattern === "function" || pattern instanceof Function) && value instanceof pattern)
return true;
else if (pattern instanceof Pattern)
return pattern.guard(value);
else if (pattern instanceof Interface)
return pattern.match(value);
return false;
};
Specialisation.prototype = {
match: function(args) {
for (var i = 0, a = this.patterns, n = a.length; i < n; ++i)
if (!Specialisation.compatible(args[i], a[i]))
return MATCH_FAIL;
return this.func.apply(this.context, args);
}
};
/**** Begin Pattern ****/
function Pattern(guard) {
this.guard = guard;
}
function GUARD(func) {
return new Pattern(func);
}
function GUARD_IS(right) {
return new Pattern(function(val) {
return val === right;
});
}
/**** Begin Interface ****/
function Interface(obj) {
if (!(this instanceof Interface))
return new Interface(obj);
for (var x in obj)
if (obj.hasOwnProperty(x))
this[x] = obj[x];
}
Interface.getSkeleton = function(obj) {
var r = {};
for (var x in obj)
if (obj.hasOwnProperty(x))
r[x] = typeof obj[x];
return new Interface(r);
};
Interface.prototype = {
match: function(value) {
for (var x in this)
if (this.hasOwnProperty(x) && !Specialisation.compatible(value[x], this[x]))
return false;
return true;
}
};
return {
create: create,
Interface: Interface,
GUARD: GUARD,
GUARD_IS: GUARD_IS,
MATCH_ANY: MATCH_ANY
};
})();
I'm sure I could think of some more (noticeably, my zip() function is missing... anyone know where that got to?). I'd quite like to include my Javascript cells implementation, which is very handy, but is also, I think, on my other harddrive, which is in a defunct machine.
Bookmarks