Skip to content

Commit 9e5000c

Browse files
committed
Provide explicit return values from an event method (github issue jakesgordon#12)
* SUCCEEDED // the event transitioned successfully from one state to another * NOTRANSITION // the event was successful but no state transition was necessary (same from/to) * CANCELLED // the event was cancelled by the caller in a beforeEvent callback * ASYNC // the event is asynchronous and the caller is in control of when the transition occurs - jakesgordon#12
1 parent a5c7025 commit 9e5000c

3 files changed

Lines changed: 49 additions & 8 deletions

File tree

state-machine.js

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@ StateMachine = {
66

77
//---------------------------------------------------------------------------
88

9+
Result: {
10+
SUCCEEDED: 1, // the event transitioned successfully from one state to another
11+
NOTRANSITION: 2, // the event was successfull but no state transition was necessary
12+
CANCELLED: 3, // the event was cancelled by the caller in a beforeEvent callback
13+
ASYNC: 4, // the event is asynchronous and the caller is in control of when the transition occurs
14+
},
15+
916
Error: {
1017
INVALID_TRANSITION: 100, // caller tried to fire an event that was innapropriate in the current state
1118
PENDING_TRANSITION: 200, // caller tried to fire an event while an async transition was still pending
@@ -85,18 +92,18 @@ StateMachine = {
8592
buildEvent: function(name, map) {
8693
return function() {
8794

95+
var from = this.current;
96+
var to = map[from] || map[StateMachine.WILDCARD] || from;
97+
var args = Array.prototype.slice.call(arguments); // turn arguments into pure array
98+
8899
if (this.transition)
89100
return this.error(name, from, to, args, StateMachine.Error.PENDING_TRANSITION, "event " + name + " inappropriate because previous transition did not complete");
90101

91102
if (this.cannot(name))
92103
return this.error(name, from, to, args, StateMachine.Error.INVALID_TRANSITION, "event " + name + " inappropriate in current state " + this.current);
93104

94-
var from = this.current;
95-
var to = map[from] || map[StateMachine.WILDCARD] || from;
96-
var args = Array.prototype.slice.call(arguments); // turn arguments into pure array
97-
98105
if (false === StateMachine.beforeEvent(this, name, from, to, args))
99-
return;
106+
return StateMachine.CANCELLED;
100107

101108
if (from !== to) {
102109

@@ -107,18 +114,20 @@ StateMachine = {
107114
StateMachine.enterState( fsm, name, from, to, args);
108115
StateMachine.changeState(fsm, name, from, to, args);
109116
StateMachine.afterEvent( fsm, name, from, to, args);
117+
return StateMachine.SUCCEEDED;
110118
};
111119

112120
if (false !== StateMachine.leaveState(this, name, from, to, args)) {
113121
if (this.transition) // in case user manually called it but forgot to return false
114-
this.transition();
122+
return this.transition();
115123
}
116124

117-
return; // transition method took care of (or, if async, will take care of) the afterEvent, DONT fall through
125+
return StateMachine.ASYNC; // transition method took care of (or, if async, will take care of) the afterEvent, DONT fall through
118126
}
119127

120128
StateMachine.afterEvent(this, name, from, to, args); // this is only ever called if there was NO transition (e.g. if from === to)
121129

130+
return StateMachine.SUCCEEDED;
122131
};
123132
}
124133

state-machine.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/test_basics.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,4 +448,36 @@ test("missing 'from' allows event from any state (github issue #11) ", function(
448448

449449
});
450450

451+
//-----------------------------------------------------------------------------
452+
453+
test("event return values (github issue #12) ", function() {
454+
455+
var fsm = StateMachine.create({
456+
initial: 'stopped',
457+
events: [
458+
{ name: 'prepare', from: 'stopped', to: 'ready' },
459+
{ name: 'fake', from: 'ready', to: 'running' },
460+
{ name: 'start', from: 'ready', to: 'running' }
461+
],
462+
callbacks: {
463+
onbeforefake: function(event,from,to,a,b,c) { return false; }, // this event will be cancelled
464+
onleaveready: function(event,from,to,a,b,c) { return false; } // this state transition is ASYNC
465+
}
466+
});
467+
468+
equals(fsm.current, 'stopped', "initial state should be stopped");
469+
470+
equals(fsm.prepare(), StateMachine.SUCCEEDED, "expected event to have SUCCEEDED");
471+
equals(fsm.current, 'ready', "prepare event should transition from stopped to ready");
472+
473+
equals(fsm.fake(), StateMachine.CANCELLED, "expected event to have been CANCELLED");
474+
equals(fsm.current, 'ready', "cancelled event should not cause a transition");
475+
476+
equals(fsm.start(), StateMachine.ASYNC, "expected event to cause an ASYNC transition");
477+
equals(fsm.current, 'ready', "async transition hasn't happened yet");
478+
479+
equals(fsm.transition(), StateMachine.SUCCEEDED, "expected async transition to have SUCCEEDED");
480+
equals(fsm.current, 'running', "async transition should now be complete");
481+
482+
});
451483

0 commit comments

Comments
 (0)