@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 todefineImplementation
has 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 toregisterExtensions
to 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/interface
Acknowledgments
Interface
was inspired by C# extension methods.
See Also
License
MIT