Comparing version
{ | ||
"name": "phaze", | ||
"version": "0.0.4", | ||
"version": "0.0.5", | ||
"description": "Finite state machine for Node robotics", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -36,34 +36,54 @@  | ||
### Nesting | ||
- A state machine can be nested within the state of an outer state machine. | ||
- Construction and initialisation of the inner state machine is done within the **"do"** function of a state. | ||
| ||
## Usage | ||
```javascript | ||
/*** | ||
/*************** | ||
STATES | ||
***/ | ||
var stateA = { | ||
***************/ | ||
var startState = { | ||
do: function () { | ||
}, | ||
outputEvent: 'testEvent' | ||
outputEvent: 'startEvent' | ||
}; | ||
var stateB = { | ||
var walkingState = { | ||
do: function (callback) { | ||
callback(null, 'OK'); | ||
callback(null, 'Walking...'); | ||
}, | ||
outputEvent: 'walkEvent' | ||
}; | ||
// no outputEvent will cause the state machine to exit the loop | ||
var runningState = { | ||
do: function (callback) { | ||
callback(null, 'Running...'); | ||
} | ||
}; | ||
/*** | ||
TRANSITION | ||
***/ | ||
var transition = { | ||
eventId: 'testEvent', | ||
from: ['stateA'], | ||
to: 'stateB' | ||
/*************** | ||
TRANSITIONS | ||
***************/ | ||
var transition1 = { | ||
eventId: 'startEvent', | ||
from: ['startState'], | ||
to: 'walkingState' | ||
}; | ||
/*** | ||
STATE PERSISTENCE FUNCTIONS | ||
***/ | ||
var transition2 = { | ||
eventId: 'walkEvent', | ||
from: ['walkingState'], | ||
to: 'runningState' | ||
}; | ||
/*************** | ||
STATE PERSISTENCE FUNCTIONS (these can wrap database calls etc.) | ||
***************/ | ||
var getStateFunc = function (callback) { | ||
callback(null, 'stateA'); | ||
callback(null, 'startState'); | ||
}; | ||
@@ -80,3 +100,3 @@ | ||
// initialise the state machine | ||
// initialise - first argument is the number of times the machine will loop (0 = infinite) | ||
stateMachine.initialise(1, getStateFunc, saveStateFunc, function (err) { | ||
@@ -86,12 +106,14 @@ if (err) | ||
stateMachine.addState('stateA', stateA); | ||
stateMachine.addState('stateB', stateB); | ||
stateMachine.addTransition(transition); | ||
stateMachine.addState('startState', startState); | ||
stateMachine.addState('walkingState', walkingState); | ||
stateMachine.addState('runningState', runningState); | ||
stateMachine.addTransition(transition1); | ||
stateMachine.addTransition(transition2); | ||
// start the machine | ||
stateMachine.start('testEvent', function (err, result) { | ||
// start the machine and confirm the final result | ||
stateMachine.start('startEvent', function (err, result) { | ||
if (err) | ||
return done(err); | ||
expect(result).to.equal('OK'); | ||
expect(result).to.equal('Running...'); | ||
done(); | ||
@@ -98,0 +120,0 @@ }) |
@@ -27,18 +27,34 @@ /** | ||
it('can transition to the next state and execute go function and then exit', function (done) { | ||
it('can transition from one state to the next and execute go function', function (done) { | ||
var self = this; | ||
var stateA = { | ||
self.__currentState = 'startState'; | ||
var startState = { | ||
do: function () { | ||
}, | ||
outputEvent: 'startEvent' | ||
}; | ||
var stateA = { | ||
do: function (callback) { | ||
callback(null, 'Result from stateA'); | ||
}, | ||
outputEvent: 'testEvent' | ||
}; | ||
var stateB = { | ||
do: function (callback) { | ||
callback(null, 'OK'); | ||
callback(null, 'Result from stateB'); | ||
} | ||
}; | ||
var transition = { | ||
var transition1 = { | ||
eventId: 'startEvent', | ||
from: ['startState'], | ||
to: 'stateA' | ||
}; | ||
var transition2 = { | ||
eventId: 'testEvent', | ||
@@ -52,5 +68,7 @@ from: ['stateA'], | ||
var getStateFunc = function (callback) { | ||
callback(null, 'stateA'); | ||
callback(null, self.__currentState); | ||
}; | ||
var saveStateFunc = function (state, callback) { | ||
self.__currentState = state; | ||
callback(); | ||
@@ -63,12 +81,14 @@ }; | ||
stateMachine.addState('startState', startState); | ||
stateMachine.addState('stateA', stateA); | ||
stateMachine.addState('stateB', stateB); | ||
stateMachine.addTransition(transition); | ||
stateMachine.addTransition(transition1); | ||
stateMachine.addTransition(transition2); | ||
// test the event | ||
stateMachine.__trigger('testEvent', function (err, result) { | ||
stateMachine.start('startEvent', function (err, result) { | ||
if (err) | ||
return done(err); | ||
expect(result).to.equal('OK'); | ||
expect(result).to.equal('Result from stateB'); | ||
done(); | ||
@@ -141,3 +161,3 @@ }) | ||
stateMachine.initialise(1, getStateFunc, saveStateFunc, function (err) { | ||
stateMachine.initialise(2, getStateFunc, saveStateFunc, function (err) { | ||
if (err) | ||
@@ -154,9 +174,9 @@ return done(err); | ||
// test the event | ||
stateMachine.__trigger('testEvent', function (err) { | ||
stateMachine.start('testEvent', function (err) { | ||
if (err) | ||
return done(err); | ||
console.log(self.counter); | ||
if (self.counter.funcBCount == 1 && | ||
self.counter.funcCCount == 1) | ||
done(); | ||
@@ -167,2 +187,133 @@ }); | ||
}); | ||
it('can nest a state machine inside a state', function (done) { | ||
var self = this; | ||
/* | ||
Outer state machine | ||
*/ | ||
self.__currentState = 'startState'; | ||
var startState = { | ||
do: function () { | ||
}, | ||
outputEvent: 'startEvent' | ||
}; | ||
var stateA = { | ||
do: function (callback) { | ||
var __this = this; | ||
/* | ||
Inner state machine | ||
*/ | ||
__this.__currentState = 'innerStartState'; | ||
var innerStartState = { | ||
do: function () { | ||
}, | ||
outputEvent: 'innerStartEvent' | ||
}; | ||
var innerStateA = { | ||
do: function (callback) { | ||
callback(null, 'Result from innerStateA'); | ||
} | ||
}; | ||
var innerTransition1 = { | ||
eventId: 'innerStartEvent', | ||
from: ['innerStartState'], | ||
to: 'innerStateA' | ||
}; | ||
var innerGetStateFunc = function (callback) { | ||
callback(null, __this.__currentState); | ||
}; | ||
var innerSaveStateFunc = function (state, callback) { | ||
__this.__currentState = state; | ||
callback(); | ||
}; | ||
var innerStateMachine = new StateMachine(); | ||
innerStateMachine.initialise(1, innerGetStateFunc, innerSaveStateFunc, function (err) { | ||
if (err) | ||
return done(err); | ||
innerStateMachine.addState('innerStartState', innerStartState); | ||
innerStateMachine.addState('innerStateA', innerStateA); | ||
innerStateMachine.addTransition(innerTransition1); | ||
console.log('Starting inner state machine....'); | ||
// test the event | ||
innerStateMachine.start('innerStartEvent', function (err, result) { | ||
if (err) | ||
return callback(err); | ||
callback(null, 'Result from innerStateA'); | ||
}) | ||
}); | ||
}, | ||
outputEvent: 'testEvent' | ||
}; | ||
var stateB = { | ||
do: function (callback) { | ||
callback(null, 'Result from stateB'); | ||
} | ||
}; | ||
var transition1 = { | ||
eventId: 'startEvent', | ||
from: ['startState'], | ||
to: 'stateA' | ||
}; | ||
var transition2 = { | ||
eventId: 'testEvent', | ||
from: ['stateA'], | ||
to: 'stateB' | ||
}; | ||
var getStateFunc = function (callback) { | ||
callback(null, self.__currentState); | ||
}; | ||
var saveStateFunc = function (state, callback) { | ||
self.__currentState = state; | ||
callback(); | ||
}; | ||
var outerStateMachine = new StateMachine(); | ||
outerStateMachine.initialise(1, getStateFunc, saveStateFunc, function (err) { | ||
if (err) | ||
return done(err); | ||
outerStateMachine.addState('startState', startState); | ||
outerStateMachine.addState('stateA', stateA); | ||
outerStateMachine.addState('stateB', stateB); | ||
outerStateMachine.addTransition(transition1); | ||
outerStateMachine.addTransition(transition2); | ||
// test the event | ||
outerStateMachine.start('startEvent', function (err, result) { | ||
if (err) | ||
return done(err); | ||
expect(result).to.equal('Result from stateB'); | ||
done(); | ||
}) | ||
}); | ||
}); | ||
}); |
18654
38.62%409
37.71%125
21.36%