yafsm v0.0.0
yet-another-finite-state-machine
Because there simply aren't enough packages on npm yet. 
Synopsis
Defining the FSM:
var door = new FSM('closed', {
'closed': ['open'],
'open': ['closed'],
})State transitions use the state method:
t.test("Moving between states", function (t) {
t.plan(4)
t.equal(door.state(), 'closed')
t.ok(!door.state('open'), "successful state change returns undefined")
t.equal('open', door.state())
t.ok(door.state('broken'), "FSM.IllegalTransitionError")
})There is also a helper function for defining stateful methods:
t.test("Defining state-aware methods", function (t) {
door.open = FSM.method('open', {
'closed': function () { return this.state('open') }
})
door.close = FSM.method('close', {
'open': function () { return this.state('closed') }
})
t.plan(2)
t.equal(door.state(), 'open')
door.close()
t.equal(door.state(), 'closed')
})Because close is not defined for the 'closed' state, further calls cause
errors:
t.test("undefined method errors", function (t) {
t.plan(2)
// if last arg is function it is assumed to be a node callback
door.close(function (err) {
t.ok(err instanceof FSM.UndefinedMethodError);
})
// otherwise the error is emitted on the next tick
door.close()
door.once('error', function (err) {
t.ok(err instanceof FSM.UndefinedMethodError);
})
})API
module.exports := FSM
FSM(initialState: String, transitions: Object<Array<String>>) => FSM
FSM := EventEmitter & {
state: (to: String?) => FSM.IllegalTransitionError?
}
FSM.method := (name: String, Object<Function>) => dispatch: Function
FSM.IllegalTransitionError := Error & {
from: String
to: String
}
FSM.UndefinedMethodError := Error & {
method: String
state: String
}new FSM(initialState, transitions)
Creates an object with a state method (described below). transitions should
be an object that where the keys are state names, and the values are arrays of
all states that can be legally transitioned to from that state. For example:
FSM.prototype.state
Given fsm instanceof FSM, fsm.state() will return the current state, and
fsm.state(newState) will attempt to transition to newState. If the
transition to newState is not allowed, an FSM.IllegalTransitionError will be
returned, otherwise nothing is returned.
A state transition causes 2 events to be emitted:
'transition', currentState, newStateis emitted before the internal state is updated.newStateis emitted after the internal state is updated.
FSM.method
Creates a stateful method that dispatches on the call-time value of
this.state(). The first argument should be a method name (which will be used
when creating UndefinedMethodError instances, and the second argument should
be an object mapping state-names to the method implementation for each state. If
the same implementation should be shared among multiple states, the state names
can be joined with a pipe character:
t.test("shared implementations of stateful methods", function (t) {
t.plan(2)
door.knock = FSM.method('knock', {
'open|closed': function () {
t.pass("knocking on door while it's " + this.state())
}
})
door.knock()
door.open()
door.knock()
})License
2-clause BSD
12 years ago