@kingjs/interface v1.0.4
@kingjs/interface
A repository of functions where every function passed to defineImplementation has assigned to its prototype every function that's passed to defineExtension, and vice-versa.
Usage
Implement any(), none(), ReadOnlyList, and Queue separately, and use an interface to attach the algorithms to the containers like this:
// containers
function ReadOnlyList(array) {
this.count = function () { return array.length; }
this.get = function (i) { return array[i]; }
}
function Queue() {
var array = [];
this.count = function () { return array.length; }
this.push = function (x) { array.push(x); }
this.pop = function () { return array.unshift(); }
}
// algorithms
function any() {
return this.count() > 0;
}
function none() {
return this.count() == 0;
}
// interface
var Interface = require('@kingjs/interface');
var interface = new Interface();
interface.registerImplementations([ ReadOnlyList, Queue ]);
interface.registerExtensions({
any: any,
none: none
});
// tests
var testList = new ReadOnlyList([1, 2, 3]);
var testQueue = new Queue();
var actual = {
testList: {
any: testList.any(),
none: testList.none()
},
testQueue: {
any: testQueue.any(),
none: testQueue.none()
}
};outputs:
{
testList: {
any: true,
none: false
},
testQueue: {
any: false,
none: true
}
};Modules
Separate the module containing the containers, from the module containing the algorithms, from the interface that joins them together, like this:
iCountable.js
var Interface = require('@kingjs/interface');
var iCountable = new Interface();
module.exports = iCountable;
> containers.js
```js
function ReadOnlyList(array) {
this.count = function () { return array.length; }
this.get = function (i) { return array[i]; }
}
function Queue() {
var array = [];
this.count = function () { return array.length; }
this.push = function (x) { array.push(x); }
this.pop = function () { return array.unshift(); }
}
var interface = require('./iCountable.js');
interface.registerImplementations([ ReadOnlyList, Queue ]);
exports.ReadOnlyList = ReadOnlyList;
exports.Queue = Queue;algorithms.js
function any() { return this.count() > 0; } function none() { return this.count() == 0; }
var interface = require('./iCountable.js'); interface.registerExtensions({ any: any, none: none });
> client.js
```js
require('./algorithms.js');
var Containers = require('./containers.js');
var ReadOnlyList = Containers.ReadOnlyList;
var Queue = Containers.Queue;
var testList = new ReadOnlyList([1, 2, 3]);
var testQueue = new Queue();
var actual = {
testList: {
any: testList.any(),
none: testList.none()
},
testQueue: {
any: testQueue.any(),
none: testQueue.none()
}
};API
declare class Interface {
constructor(bases?: Interface[]);
defineExtension(
name: string, extension: Function
): Function;
registerExtensions(
extensions: { [index: string]: Function }
);
defineImplementation(
implementation: Function
): Function;
registerImplementations(
implementations: Function[]
): void;
bases(): IEnumerable<Interface>;
implementations(): IEnumerable<Function>;
extensions(): IEnumerable<{
name: string,
func: Function
}>;
}
interface IEnumerable<T> {
getEnumerator(): {
moveNext(): { Boolean },
current: T
}
}Methods
constructor: A repository of functions where every function passed todefineImplementationhas assigned to its prototype every function that's passed todefineExtension, and vice-versa.
defineExtension: Attaches an extension to the prototype of functions previously passed toregisterImplementations. Retains the extension for assignment to subsequent implementations.
registerExtensions: Batch registers extensions.
registerImplementations: Calls itself on any base interfaces. Assigns name/function pairs previously passed toregisterExtensionsto the implementation prototype. Retains the implementations for future extension.
defineImplementation: Batch registers implementations.
bases: Base interfaces.
implementations: Retained implementations.
extensions: Retained extensions.
Remarks
Extension names occupy a global namespace. To prevent collisions, each developer should affix a unique prefix to their algorithm names. For example, I plan on implementing the LINQ suite of algorithms and will prefix them all with Linq. This way, LinqAny will not conflict with Joe's implementation which he'll name JoesAny.
Install
With npm installed, run
$ npm install @kingjs/interfaceAcknowledgments
Interface was inspired by C# extension methods.
See Also
License
MIT