jsinterface
Version:
Implement duck-type interfaces in Node JS
86 lines (66 loc) • 2.25 kB
JavaScript
var errors = require('./errors');
module.exports = new JsInterfaceContainer();
function JsInterfaceContainer() {
this._definitions = {};
}
JsInterfaceContainer.prototype.createContainer = function() {
return new JsInterfaceContainer();
};
JsInterfaceContainer.prototype.define = function(interface) {
if (!interface) throw new errors.ArgumentNullError('Argument cannot be null: interface');
if (!interface.name) throw new errors.ArgumentNullError('Argument cannot be null: interface.name');
var result = this._definitions[interface.name] = createInterface(interface);
return result;
};
JsInterfaceContainer.prototype.complies = function(obj, interface) {
return this._definitions[interface].complies(obj);
};
JsInterfaceContainer.prototype.checkComplies = function(obj, interface) {
this._definitions[interface].checkComplies(obj);
};
JsInterfaceContainer.prototype.wrap = function(obj, interface) {
return this._definitions[interface].wrap(obj);
};
// -- private --
function createInterface(interface) {
return {
complies: complies.bind(null, false),
checkComplies: complies.bind(null, true),
wrap: wrapInterface
};
function complies(throwError, obj) {
var ok = true;
if (interface.methods) {
interface.methods.forEach(function(method) {
if (typeof obj[method] !== 'function') {
if (throwError) throw new errors.MissingMethodError('Missing required method: ' + method);
ok = false;
}
});
}
if (interface.properties) {
interface.properties.forEach(function(prop) {
if (typeof obj[prop] === 'undefined') {
if (throwError) throw new errors.MissingPropertyError('Missing required property: ' + prop);
ok = false;
}
});
}
return ok;
}
function wrapInterface(obj) {
var wrapper = {};
complies(true, obj);
if (interface.methods) {
interface.methods.forEach(function(method) {
wrapper[method] = obj[method].bind(obj);
});
}
if (interface.properties) {
interface.properties.forEach(function(prop) {
Object.defineProperty(wrapper, prop, {get: function() { return obj[prop]; }});
});
}
return wrapper;
}
}