diff --git a/README.md b/README.md index a2345286..083732b0 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,51 @@ for es6 classes to ------------------ ``` +const stm = require('statetranstion-mixin'); + +const actions = stm.prepareActions({ +start: { + stopped: { + target: "running", + during: "starting", + timeout: 10 + } +}, +stop: { + running: { + target: "stopped", + during: "stopping", + timeout: 5 + }, + starting: { + target: "stopped", + during: "stopping", + timeout: 10 + } +} +}); + +class BaseClass {} + +class StatefullClass extends stm.StateTransitionMixin(BaseClass, actions, 'stopped') { +_start() { + return new Promise((f, r) => { + setTimeout(() => { + f(this) + }, 10); + }); +} +} + +stm.defineActionMethods(StatefullClass.prototype, actions); + +myObject = new StatefullClass(); + +myObject.start().then( (o) => console.log('started == ${o.state}')); +console.log('starting == ${myObject.state}'); + +myObject.stop().then( (o) => console.log('stopped == ${o.state}')); +console.log('stopping == ${myObject.state}'); ``` diff --git a/StateTransitionMixin.js b/StateTransitionMixin.js index cd7d1d28..72d584cf 100644 --- a/StateTransitionMixin.js +++ b/StateTransitionMixin.js @@ -72,6 +72,8 @@ function thisResolverPromise() { } module.exports.defineActionMethods = function (object, actions) { + console.log(`${JSON.stringify(actions,undefined,1)}`); + Object.keys(actions).forEach(actionName => { const action = actions[actionName]; const privateActionName = '_' + actionName; @@ -84,29 +86,30 @@ module.exports.defineActionMethods = function (object, actions) { Object.defineProperty(object, actionName, { value: function () { - console.log(`${actionName}`); - - /* - if (this.state === transition.during) { - return this._transitionPromise; + if (this._transition) { + if (this.state === this._transition.during) { + return this._transitionPromise; + } + if (this.state === this._transition.target) { + return Promise.resolve(this); + } } - if (this.state === transition.target) { - return Promise.resolve(this); - }*/ - - if (action.transitions[this.state]) { - const transition = action.transitions[this.state]; + this._transition = action.transitions[this.state]; + this.state = this._transition.during; + this._transitionPromise = this[privateActionName]().then( resolved => { - this.state = transition.target; + this.state = this._transition.target; this._transitionPromise = undefined; + this._transition = undefined; return this; }, rejected => { - this.error(level => `Executing ${transition.name} transition leads to ${rejected}`); + this.error(level => `Executing ${this._transition.name} transition leads to ${rejected}`); this.state = 'failed'; this._transitionPromise = undefined; + this._transition = undefined; return Promise.reject(reject); }); diff --git a/tests/simple.js b/tests/simple.js index cbd07bb3..135f2ad8 100644 --- a/tests/simple.js +++ b/tests/simple.js @@ -59,10 +59,39 @@ describe('states', function () { }, done); }); - it('can be stopped', function (done) { + it('and stoped', function (done) { o1.stop().then(() => { assert.equal(o1.state, 'stopped'); done(); }, done); }); + + it('can be started while starting', function (done) { + assert.equal(o1.state, 'stopped'); + + o1.start().then(() => {}); + + assert.equal(o1.state, 'starting'); + + o1.start().then(() => { + assert.equal(o1.state, 'running'); + done(); + }, done).catch(done); + }); + + xit('can be stopped while starting', function (done) { + o1.stop().then(() => { + assert.equal(o1.state, 'stopped'); + + o1.start().then(() => {}); + + assert.equal(o1.state, 'starting'); + + o1.stop().then(() => { + assert.equal(o1.state, 'stopped'); + done(); + }, done).catch(done); + }); + }); + });