heterarchy
Version:
Cooperative multiple inheritance for CoffeeScript, á-la Python
166 lines (141 loc) • 5.73 kB
JavaScript
// Generated by CoffeeScript 1.10.0
(function() {
var assert, copyOwn, every, find, generate, head, hierarchy, inherited, isEmpty, isEqual, isJavaScriptClass, javaScriptClassNames, javaScriptClasses, map, memoize, merge, mro, partial, reduce, ref, reject, reparent, some, tail, without,
slice = [].slice,
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
hasProp = {}.hasOwnProperty,
indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
ref = require('underscore'), head = ref.head, tail = ref.tail, map = ref.map, find = ref.find, some = ref.some, without = ref.without, isEmpty = ref.isEmpty, every = ref.every, memoize = ref.memoize, reject = ref.reject, partial = ref.partial, isEqual = ref.isEqual, reduce = ref.reduce;
assert = function(value, error) {
if (!value) {
throw new Error(error != null ? error : "Assertion failed");
}
};
exports.multi = function() {
var bases;
bases = 1 <= arguments.length ? slice.call(arguments, 0) : [];
return generate(merge(map(bases, mro).concat([bases])));
};
generate = memoize(function(linearization) {
var Result, next;
next = head(linearization);
if (isEqual(linearization, hierarchy(next))) {
return next;
} else {
return Result = (function(superClass) {
var class1;
extend(Result, superClass);
function Result() {
return class1.apply(this, arguments);
}
Result.prototype.__mro__ = linearization;
class1 = reparent(next, Result, next.prototype.constructor);
copyOwn(next, Result);
copyOwn(next.prototype, Result.prototype, partial(reparent, next, Result));
return Result;
})(generate(tail(linearization)));
}
});
copyOwn = function(from, to, project) {
var key, value;
if (project == null) {
project = function(x) {
return x;
};
}
for (key in from) {
if (!hasProp.call(from, key)) continue;
value = from[key];
if (!to.hasOwnProperty(key)) {
to[key] = project(value);
}
}
return to;
};
reparent = function(oldklass, newklass, value) {
var newsuper, oldsuper, superctor;
if (!(value instanceof Function)) {
return value;
} else if (value === oldklass.prototype.constructor && inherited(oldklass) === Object) {
superctor = inherited(newklass).prototype.constructor;
return function() {
superctor.apply(this, arguments);
return value.apply(this, arguments);
};
} else {
newsuper = inherited(newklass).prototype;
oldsuper = oldklass.__super__;
return function() {
oldklass.__super__ = newsuper;
try {
return value.apply(this, arguments);
} finally {
oldklass.__super__ = oldsuper;
}
};
}
};
merge = function(inputs) {
var next, results;
results = [];
while (!isEmpty(inputs)) {
next = find(map(inputs, head), function(candidate) {
return every(inputs, function(input) {
return indexOf.call(tail(input), candidate) < 0;
});
});
assert(next != null, "Inconsistent multiple inheritance");
inputs = reject(map(inputs, function(lst) {
return without(lst, next);
}), isEmpty);
results.push(next);
}
return results;
};
javaScriptClassNames = ["Array", "Boolean", "Date", "Error", "Function", "Number", "RegExp", "String", "Object", "EvalError", "RangeError", "ReferenceError", "SyntaxError", "TypeError", "URIError", "Symbol", "Int8Array", "Uint8Array", "Uint8ClampedArray", "Int16Array", "Uint16Array", "Int32Array", "Uint32Array", "Float32Array", "Float64Array", "Map", "Set", "WeakMap", "WeakSet", "ArrayBuffer", "DataView", "Promise", "Generator", "GeneratorFunction", "Reflect", "Proxy"];
javaScriptClasses = reduce(javaScriptClassNames, function(classes, name) {
classes[global[name]] = global[name];
return classes;
}, {});
isJavaScriptClass = function(cls) {
return javaScriptClasses[cls] === cls;
};
exports.mro = mro = function(cls) {
var result;
if ((cls == null) || (cls.prototype == null)) {
return [];
} else if (!cls.prototype.hasOwnProperty('__mro__')) {
result = [cls].concat(mro(inherited(cls)));
if (!isJavaScriptClass(cls)) {
cls.prototype.__mro__ = result;
}
return result;
} else {
return cls.prototype.__mro__;
}
};
exports.inherited = inherited = function(cls) {
var ref1;
return (ref1 = Object.getPrototypeOf(cls.prototype)) != null ? ref1.constructor : void 0;
};
exports.hierarchy = hierarchy = function(cls) {
if (cls == null) {
return [];
} else {
return [cls].concat(hierarchy(inherited(cls)));
}
};
exports.isinstance = function() {
var classes, obj;
obj = arguments[0], classes = 2 <= arguments.length ? slice.call(arguments, 1) : [];
return exports.issubclass.apply(exports, [obj != null ? obj.constructor : void 0].concat(slice.call(classes)));
};
exports.issubclass = function() {
var classes, klass, linearization;
klass = arguments[0], classes = 2 <= arguments.length ? slice.call(arguments, 1) : [];
linearization = mro(klass);
return some(classes, function(cls) {
return indexOf.call(linearization, cls) >= 0;
});
};
}).call(this);