cycle-plugins
v0.1.1
Published
Provides observable-based plugins to cycle.js applications.
Downloads
4
Maintainers
Readme
cycle-plugins
Provides observable-based plugins to cycle.js applications.
Installation
npm i cycle-plugins --save
Scripts
NOTE: Make sure you've installed all dependencies using npm install
first.
To generate documentation: npm run doc
. This will create documentation in the
build/docs
folder.
To run unit tests: npm test
API
Plugins
Static class for registering and consuming Plugin instances dynamically.
Kind: global namespace
plugins.register(plugins)
Makes one or more Plugins available to consumers.
Kind: instance method of Plugins
| Param | Type | Description | | --- | --- | --- | | plugins | Plugin | Array.<Plugin> | One or more Plugin instances to make available to consumers. |
Example
Plugins.register(new Plugin({
name: 'console',
log: function log(msg) { ... }
}));
Plugins.get({name: 'console'}).first()
.tap(console => console.log('hello'));
plugins.unregister(plugins)
Makes a Plugin unavailable to consumers.
Kind: instance method of Plugins
| Param | Type | Description | | --- | --- | --- | | plugins | Plugin | Array.<Plugin> | One or more Plugin instances to unregister. |
Example
var plugin = new Plugin({name: 'temp'});
Plugins.register(plugin); // available to consumers
Plugins.unregister(plugin); // unavailable to consumers
plugins.get(criteria)
Returns an Observable populated with an array of
Plugin instances matching the specified criteria.
The array contains a utility method called toDAG
that will return a DAG instance you can use to
iterate safely over the returned Plugin instances
in a way that respects the index
and after
properties of each Plugin.
Kind: instance method of Plugins
Throws:
- Error Invalid criteria was specified.
| Param | Type | Description | | --- | --- | --- | | criteria | Object | A map of criteria to apply against each registered Plugin. Only Plugin instances matching the specified criteria will be included in the resulting Observable. |
Example
// retrieve a single Plugin by name
var single$ = Plugins.get({name: 'my-one-plugin'}).first();
Example
// retrieve all registered Plugin instances
var allPlugins$ = Plugins.get(); // or Plugins.get({})
Example
// retrieve all Plugin instances targeting a specific type
var targeted$ = Plugins.get({targetType: MyClass});
Example
// retrieve Plugin instances matching a specific filter;
// the Plugin would need 'my-criteria' in its `filter.any`
// string array and NOT in its `filter.none` string array.
var filtered$ = Plugins.get({filter: 'my-criteria'});
Example
// iterating through Plugins concurrently and in a
// dependency-safe order:
let savePlugins$ = Plugins.get({
targetType: MyClass, filter: 'save'
});
function save() {
return savePlugins$.map(plugins =>
new Observable(observer =>
plugins.toDAG().forEach(
(plugin, next) => plugin.doSomething(), next(),
(err) => err ? observer.error(err) : observer.next()
);
));
}
Plugin
Kind: global class
Inherits: Broker
Properties
| Name | Type | Default | Description | | --- | --- | --- | --- | | name | String | | The name of this plugin. | | index | Number | 0 | Provides a way to order multiple Plugins whenever a sequence is requested. | | after | Array.<String> | [] | Provides a way to order multiple Plugins based on dependencies. Ensures that this Plugin will be sequenced after the specified Plugin names. If you prepend a name with ?, it will be treated as an optional dependency. | | enabled | Boolean | true | Some consumers may use this property to determine which Plugins should be consumed or which can be skipped during iteration. | | targetType | function | Object | Used in conjunction with Plugins.get to ensure both Plugin creators and Plugin consumers agree on who can consume this Plugin instance. | | filter | Filter | {any:[], none:[]} | A way to restrict the list of Plugins retrieved by Plugins.get at runtime. |
- Plugin
- new Plugin(props)
- .Events : Object
new Plugin(props)
An extensible object.
| Param | Type | Description |
| --- | --- | --- |
| props | Object | A map of property names and values to apply to the Plugin instance. The only required property is name
. |
Example
import {extend, matches} from 'lodash';
const COMMAND_PROPS = { ... };
class Command extends Plugin
constructor(props) {
super(extend({}, COMMAND_PROPS, props));
Plugins.register(this);
}
execute() {}
undo() {}
}
class RecordCommand extends Command {
constructor(props) {
super({
targetType: Record,
enabled: User.hasPrivilege(props.name)
});
}
}
class SaveRecord extends RecordCommand
constructor() {
super({name: 'save-record');
}
execute() { ... }
undo() { ... }
}
class DeleteRecord extends RecordCommand
constructor() {
super({name: 'delete-record');
}
execute() { ... }
undo() { ... }
}
class Record extends Broker {
constructor() {
this.commands$ = Plugins.get({
baseType: RecordCommand,
targetType: Record,
enabled: true
});
}
save() {
return this.commands$
.filter(matches({name: 'save-record'}))
.map(command => command.execute(this))
.tap(() => this.emit('record-saved'))
.toPromise();
}
}
Plugin.Events : Object
Events specific to Plugins.
Kind: static property of Plugin
Properties
| Name | Type | Description | | --- | --- | --- | | PLUGIN_CHANGED | String | A property on the plugin has changed. Emit this event when you wish for any search criteria passed to Plugins.get to be re-evaluated, with observers notified of any changes. |
DAG (Directed Acyclic Graph)
Kind: global class
new DAG(plugins)
Provides a dependency-safe way to iterate through plugins.
Throws:
- Error If a dependent Plugin is not optional and not in the set of Plugins provided to the constructor, an error will be thrown. You can mark a dependency as optional by prepending it with a question mark. See the documentation for Plugin for more information.
| Param | Type | Description | | --- | --- | --- | | plugins | Plugin | Array.<Plugin> | One or more Plugin instances the DAG should manage. |
Example
var dag = new DAG(pluginA, pluginB, pluginC);
dag.forEach(function iterate(plugin, next) {
// do something with plugin
next(); // invoke this callback with the next plugin
// if you wish to stop iteration immediately, invoke
// next with an argument: next(0) or next('stop') or
// next(new Error()) -- the argument will be passed
// to your success handler function
}, function finished(err) {
if (err) {
console.log('An error occurred:', err);
}
});
daG.toArray() ⇒ Array.<Plugin>
Converts the DAG into a dependency-safe sequence of Plugin instances.
Kind: instance method of DAG
Returns: Array.<Plugin> - An array of Plugin instances in dependency-safe order.
Example
var dag = new DAG(pluginA, pluginB, pluginC);
var names = dag.toArray().map(function(plugin) {
return plugin.name;
});
log(names);
daG.forEach(callback, [finish], [concurrency])
Iterates through the DAG in dependency-safe order using the specified callback function and concurrency settings.
Kind: instance method of DAG
Throws:
- Error Parameter
callback
must be a function. - Error Parameter
concurrency
must be a positive integer.
| Param | Type | Default | Description | | --- | --- | --- | --- | | callback | function | | A method that will be invoked for each Plugin instance. Arguments will be: - {Plugin} plugin - the current plugin - {Function} next - method to invoke to continue iteration - {Number} percent - a number between 0 and 100 indicating how much of the DAG has been processed | | [finish] | function | | An optional method to invoke when the DAG has been completely processed. If an error has occurred or the iteration ended early, the only argument will be the exit reason. | | [concurrency] | Number | 5 | How many Plugins to iterate concurrently. The number must be a positive integer. |
Example
new DAG(pluginA, pluginB, pluginC)
.forEach((plugin, next, percent) => {
log(`running ${plugin.name} - ${percent}% complete`);
next('stop'); // stop iterating early
}, err => {
if (err) {
log('stopped early because:', err);
}
});