npm package: @kingjs/interface
Description: 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.
Author: Chris King
Latest version: 1.0.4
Deprecated: see @kingjs/pipe; no global state

# @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:

```js
// 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:

```js
{
  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
```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
```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

```ts
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 to `defineImplementation` has assigned to its prototype every function that's passed to `defineExtension`, and vice-versa.

> `defineExtension`: Attaches an extension to the prototype of functions previously passed to `registerImplementations`. 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 to `registerExtensions` 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](https://npmjs.org/) installed, run

```
$ npm install @kingjs/interface
```

## Acknowledgments
`Interface` was inspired by C# extension methods. 

## See Also
- [C# extension methods](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/extension-methods)

## License

MIT