yaf

yafsm

Yet-another-finite-state-machine

Showing:

Popularity

Downloads/wk

1K

GitHub Stars

2

Maintenance

Last Commit

8yrs ago

Contributors

1

Package

Dependencies

1

Size (min+gzip)

0.7KB

License

BSD-2-Clause

Type Definitions

Tree-Shakeable

No?

Categories

Readme

yet-another-finite-state-machine

Because there simply aren't enough packages on npm yet. Build Status

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, newState is emitted before the internal state is updated.
  • newState is 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

Rate & Review

Great Documentation0
Easy to Use0
Performant0
Highly Customizable0
Bleeding Edge0
Responsive Maintainers0
Poor Documentation0
Hard to Use0
Slow0
Buggy0
Abandoned0
Unwelcoming Community0
100
No reviews found
Be the first to rate

Alternatives

No alternatives found

Tutorials

No tutorials found
Add a tutorial