ember-pipeline
Railway oriented programming in Ember. To install:
ember install ember-pipeline
Philosophy
ember-pipeline
allows you to compose a pipeline of (promise aware) methods on an object using "railway oriented programming". That is, if any of the methods in the pipeline returns a CANCEL
token, the entire pipeline exits and can be optionally handled by another method. If the host Ember.Object
is destroyed, the pipeline is aborted as well.
For example:
import Ember from ' ember ' ;
import { pipeline , step , CANCEL } from ' ember-pipeline ' ;
const { computed , get } = Ember ;
export default Component . extend ( {
fetchStoreLocations : computed ( function ( ) {
return pipeline ( this , [
step ( ' requestGeolocation ' ) ,
step ( ' fetchStoresInProximity ' ) ,
step ( ' sortStoresByDistance ' ) ,
step ( ' alwaysCancels ' )
] ) . onCancel ( ( cancellation ) => this . handleCancel ( cancellation ) ) ;
} ) ,
requestGeolocation ( ) { } ,
fetchStoresInProximity ( ) { } ,
sortStoresByDistance ( ) { } ,
alwaysCancels ( ) {
return CANCEL ( ) ;
} ,
handleCancel ( cancellation ) {
switch ( cancellation . fnName ) {
case ' requestGeolocation ' :
break ;
case ' fetchStoresInProximity ' :
break ;
case ' sortStoresByDistance ' :
break ;
default :
console . log ( ` last value: ${ cancellation . result } , reason: ${ cancellation . reason } ` ) ;
break ;
}
} ) ,
actions : {
fetchStoreLocations ( ... args ) {
return get ( this , ' fetchStoreLocations ' ) . perform ( ... args ) ;
}
}
} ) ;
Usage
First, create a pipeline using pipeline
and step
. You can also define a cancel handler:
return pipeline ( this , [
step ( ' step1 ' ) ,
step ( ' step2 ' ) ,
step ( ' step3 ' )
] ) . onCancel ( ( cancellation ) => this . handleCancel ( cancellation ) ) ;
If using inside of an Ember.Object
, you could make this a computed property:
export default Component . extend ( {
myPipeline : computed ( function ( ) {
return pipeline ( this , [
step ( ' step1 ' ) ,
step ( ' step2 ' ) ,
step ( ' step3 ' )
] ) . onCancel ( ( cancellation ) => this . handleCancel ( cancellation ) ) ;
} )
} ) ;
step
receives either a method name as a string, or a function:
[ step ( ' step1 ' ) , step ( x => x * x ) ] ;
In a step
function, return CANCEL()
to abort the pipeline:
{
step1 ( ) {
return CANCEL ( ' optional reason, can be any type ' ) ;
}
}
Then, to run the pipeline, get the reference to it and perform
it:
get ( this , ' myPipeline ' ) . perform ( ... args ) ;
pipelineInstance . perform ( ... args ) ;
You can compose new pipelines at runtime. For example:
export default Component . extend ( {
makePipeline ( steps ) {
return pipeline ( this , steps )
. onCancel ( ( cancellation ) => this . handleCancel ( cancellation ) ) ;
} ,
actions : {
normal ( ... args ) {
return this . makePipeline ( [ step ( ' step1 ' ) , step ( ' step2 ' ) ] ) . perform ( ... args ) ;
} ,
reverse ( ... args ) {
return this . makePipeline ( [ step ( ' step2 ' ) , step ( ' step1 ' ) ] ) . perform ( ... args ) ;
}
}
} ) ;
After a pipeline has been performed, you can get derived state:
get ( this , ' myPipeline ' ) . perform ( 1 , 2 , 3 ) ;
get ( this , ' myPipeline.successfulSteps.length ' ) ;
get ( this , ' myPipeline.cancelledSteps.length ' ) ;
get ( this , ' myPipeline.successfulSteps ' ) ;
get ( this , ' myPipeline.cancelledSteps ' ) ;
API
Because features are still in flux, detailed API docs are coming soon!
Roadmap
Installation
git clone <repository-url>
this repository
cd ember-pipeline
npm install
bower install
Running
Running Tests
npm test
(Runs ember try:each
to test your addon against multiple Ember versions)
ember test
ember test --server
Building
For more information on using ember-cli, visit https://ember-cli.com/ .