state()

The State module is exported as a function named state. This is used either (1) to apply a working state implementation to any owner object; or (2) to define a state expression that declares the content for a State.

SYNTAX 1
state( owner, attributes, expression )
state( owner, expression )
SYNTAX 2
state( attributes, expression )
state( expression )
state( attributes )
state()
PARAMETERS
  • owneropt : object
  • attributesopt : string
  • expressionopt : ( object | StateExpression )
RETURNS
  1. If an arbitrary owner object is provided, state() bestows owner with a new state implementation based on the supplied expression and attributes, and returns the owner’s initial State.

  2. If no owner is provided, state() creates and returns a formal StateExpression based on the contents of expression and attributes.

EXAMPLE
var owner = {};
state( owner, 'abstract', {
    aState: state( 'initial default', {
        aMethod: function () {}
    }),
    anotherState: {
        aSubstate: state
    }
});
owner = {}
state owner, 'abstract',
  aState: state 'initial default',
    aMethod: ->
  anotherState:
    aSubstate: state
DISCUSSION

Inside the definition of a StateExpression, the following uses of state are effectively equivalent, each defining a nested empty StateExpression:

expr = state({
  A: state({}),
  B: state(),
  C: state
});
expr = state
  A: state({})
  B: state()
  C: state

The latter case (C) is the preferred usage.

SEE ALSO

Getting started: The state function state()

Utility functions

bind

Causes a function to be contextually bound to the State in which it acts, providing the means to reliably reference the superstate from within that function.

SYNTAX
state.bind( fn )
PARAMETERS
  • fn : function
RETURNS

An object that boxes fn, marked with a type of state-bound-function.

EXAMPLE
var owner = {};
state( owner, {
    A: {
        ask: function ( question ) {
            if ( question == null ) return { answer: 42 };
        },
        AA: {
            ask: state.bind( function ( question ) {
                this.owner === owner;  // true
                this.superstate.call( 'ask', question );
            }),
            AAA: state('initial')
        }
    }
});

owner.ask( null );  // >>> { answer: 42 }
owner = {}
state owner,
  A:
    ask: ( question ) -> if not question? then answer: 42
    AA:
      ask: state.bind ( question ) ->
        @owner is owner  # >>> true
        @superstate.call 'ask', question
      AAA: state 'initial'

owner.ask null  # >>> { answer: 42 }
DISCUSSION

Normally a state method or event listener will be invoked in the context of the owner object. However, certain patterns may require a function to have a static reference to the State for which it acts: for example, if a state method wishes to inherit more generic behavior from an implementation located higher in the state tree.

Note that the expression this.state().superstate does not provide a lexical reference to the targeted superstate. Because the function may be inherited by a substate, the meaning of this.state() is dependent on the identity of the inheritor, and is therefore dynamic along the superstate axis.

To achieve this, the function must be wrapped in a call to state.bind, which boxes the function inside a specially typed object. Thenceforth whenever State needs to use this function, it will be recognized in its boxed form as state-bound, and then automatically unboxed and invoked in the context of the prevailing State.

The owner object, meanwhile, although no longer referenced directly as this, is still reliably available as this.owner.

If a state-bound method, event listener, etc. is inherited from a protostate, then the prevailing State will be the inheriting epistate. To capture a reference to the precise State in which a function is defined, it must be wrapped with state.fix.

SEE ALSO

Method context state.fix

fix

Causes a function to be decorated with fixed bindings that indicate the precise State in which the function is defined. This provides a reliable means to reference the lexical protostate relative to that function’s definition.

SYNTAX
state.fix( fn )
PARAMETERS
  • fn : ( autostate, protostateopt ) → function
RETURNS

An object that boxes the decorated function returned by fn, marked with a type of state-fixed-function.

EXAMPLE
var q = {}
state( q, {
    A: {
        ask: function ( question ) {
            if ( question == null ) return { answer: 42 };
        }
    }
});

var p = Object.create( q );
state( p, {
    A: {
        ask: state.fix( function ( autostate, protostate ) {
            return function ( question ) {
                return protostate.call( 'ask', question );
            };
        })
    }
});

var o = Object.create( p );
o.state('-> A');
o.ask( null );  // >>> { answer: 42 }
class Superclass
  state @::,
    A:
      ask: ( question ) -> if not question? then answer: 42

class Class
  state @::,
    A:
      ask: state.fix ( autostate, protostate ) -> ( question ) ->
        protostate.call 'ask', question

o = new Class
o.state '-> A'
o.ask null  # >>> { answer: 42 }
DISCUSSION

For a function to reliably access either the State in which it is defined, or important related States such as its protostate, the function must be lexically bound to its host State by enclosing it within a decorator, and wrapping this in a call to state.fix.

The decorator is provided as a function that defines parameters autostate and optionally protostate, and returns the function fn that is to be fixed. Calling fix then boxes the decorator inside a specially typed object. Thenceforth whenever State implements this function as a method, event listener, etc. for a State, it will recognize the object as a state-fixed function, which will be automatically unboxed and partially applied with the host State as autostate, and its immediate protostate as protostate.

The fixed, enclosed fn is thusly bestowed with full lexical awareness of the particular State environment in which it exists.

SEE ALSO

Lexical bindings state.bind

own

Ensures that, for a given owner, the State returned by a queried selector is both real and not an inherited protostate.

SYNTAX
state.own( owner, selector )
state.own( owner, selector, expr )
PARAMETERS
  • owner : object
  • selector : string
  • expropt : ( object | StateExpression )
RETURNS

Either the new real epistate, or null if selector does not identify a State that is heritable by owner.

DESCRIPTION

Causes the inherited protostate or virtual epistate identified by selector to be realized, if necessary, within the state tree of owner. If a realization does occur, the new epistate can be augmented by the optional expr.

EXAMPLE
function Class () {}
var p = Class.prototype;
state( p, { A: state } );

var o = new Class;
o.state('A').on('enter', function () {});           // [1]
state.own( o, 'A' ).on('enter', function () {});    // [2]
class Class
  state @::, A: state

p = Class::
o = new Class
o.state('A').on 'enter', ->         # [1]
state.own( o, 'A' ).on 'enter', ->  # [2]
  1. Unexpected: the enter event listener is added to state A of p, not o. The incipient instance o inherits its entire state tree from p, so o.state('A') is equal to p.state('A').

  2. Calling state.own(o,'A') instead of o.state('A') ensures that the returned State is real (not virtual) and that its owner is o (not a prototype). The event listener will be held in the state tree of o, as expected.

SEE ALSO

Protostates and epistates Virtual epistates

extend

Defines a state expression that declares one or more paths to parastates from which the expressed State will inherit.

SYNTAX
state.extend( parastates )
state.extend( parastates, expression )
state.extend( parastates, attributes )
state.extend( parastates, attributes, expression )
PARAMETERS
  • parastates : string — Comma separated list of selector paths to parastates.
  • attributesopt : string
  • expressionopt : ( object | StateExpression )
RETURNS

A StateExpression with a corresponding parastates property.

EXAMPLE
var q = {};
state( q, {
    A: state({
        data: { a: 'a' }
    }),
    X: state( 'abstract', {
        data: { x: 24 }
    })
});

var p = Object.create( q );
state( p, {
    A: state({
        AA: state.extend( 'X', {
            data: { aa: 'aa' }
        })
    }),
    Y: state( 'abstract', {
        data: { y: 25 }
    })
});

var o = Object.create( p );
state( o, {
    B: state.extend( 'X, Y', {
        data: { b: 'b' }
    })
});


o.state('-> AA');
o.data();           // >>> { aa: 'aa', x: 24, a: 'a' }
o.state('-> B');
o.data();           // >>> { b: 'b', x: 24, y: 25 }
class Superclass
  state @::,
    A: state
      data: { a: 'a' }
    X: state 'abstract',
      data: { x: 24 }

class Class extends Superclass
  state @::,
    A: state
      AA: state.extend 'X',
        data: { aa: 'aa' }
    Y: state 'abstract',
      data: { y: 25 }

o = new Class
state o,
  B: state.extend 'X, Y',
    data: { b: 'b' }


o.state '-> AA'
o.data()         # >>> { aa: 'aa', x: 24, a: 'a' }
o.state '-> B'
o.data()         # >>> { b: 'b', x: 24, y: 25 }
SEE ALSO

Parastates and composition


State

A State models a set of behaviors on behalf of an owner object. The owner may undergo transitions that change its current state from one to another, and in so doing adopt a different set of behaviors.

Distinct behaviors are modeled in each state by defining method overrides, to which calls made on the owner will be redirected so long as a state remains current.

States are structured as a rooted tree, where substates inherit from a single superstate. While a substate is current, it and all of its ancestor superstates are active.

In addition, a state also recognizes the owner object’s prototypal inheritance, identifying an identically named and positioned state in the prototype as its protostate. Stateful behavior is inherited from protostates first, then from superstates.

SEE ALSO

Overview States Object model State

Properties

name

The string name of this state. For the unique case of a RootState, this value will be the empty string ''.

SYNTAX
this.name
EXAMPLE
var mover = {};
state( mover, {
    Moving: {
        Running: state('initial')
    }
});

mover.state().name;    // >>> "Running"
mover.state().path();  // >>> "Moving.Running"
mover = {}
state mover,
  Moving:
    Running: state 'initial'

mover.state().name    # >>> "Running"
mover.state().path()  # >>> "Moving.Running"
SEE ALSO

path

State constructor

owner

References the object that is the owner of this state.

SYNTAX
this.owner
EXAMPLE
function Mover() {}
state( Mover.prototype, {
    Moving: state('initial')
});

var mover = new Mover;
mover.state().owner === mover;  // >>> true
class Mover
  state @::,
    Moving: state 'initial'

mover = new Mover
mover.state().owner is mover  # >>> true
SEE ALSO

State constructor

root

References the RootState of the state tree to which this state belongs.

SYNTAX
this.root
EXAMPLE
var mover = {};
state( mover, {
    Moving: {
        Running: state
    }
});

mover.state().root;          // >>> State ''
mover.state('').root;        // >>> State ''
mover.state('Moving').root;  // >>> State ''
mover = {}
state mover,
  Moving:
    Running: state

mover.state().root          # >>> State ''
mover.state('').root        # >>> State ''
mover.state('Moving').root  # >>> State ''
SEE ALSO

The root state State constructor

superstate

References the State that is this state’s immediate superstate.

SYNTAX
this.superstate
EXAMPLE
var mover = {};
state( mover, {
    Moving: {
        Running: state
    }
});

mover.state('Running').superstate;  // >>> State 'Moving'
mover.state('Moving').superstate;   // >>> State ''
mover.state('').superstate;         // >>> undefined
mover = {}
state mover,
  Moving:
    Running: state

mover.state('Running').superstate  # >>> State 'Moving'
mover.state('Moving').superstate   # >>> State ''
mover.state('').superstate         # >>> undefined
SEE ALSO

Superstates and substates State constructor

protostate

References the State that is this state’s immediate protostate.

SYNTAX
this.protostate
EXAMPLE
function Mover () {}
state( Mover.prototype, {
    Moving: {
        Running: state('initial')
    }
});

var mover = new Mover;
mover.state().name;              // >>> 'Running'
mover.state().protostate;        // >>> State 'Running'
mover.state().protostate.owner;  // >>> Mover.prototype
class Mover
  state @::,
    Moving:
      Running: state 'initial'

mover = new Mover
mover.state().name              # >>> 'Running'
mover.state().protostate        # >>> State 'Running'
mover.state().protostate.owner  # >>> Mover.prototype
SEE ALSO

Protostates and epistates State constructor

Attributes

State attributes are added to a state expression by preceding the expression argument of a call to state() with a space-delimited string argument that names the attributes to be applied.

EXAMPLE
state( obj, 'abstract', {
    Alive: state( 'default initial mutable', {
        update: function () { /*...*/ }
    }),
    Dead: state( 'final', {
        update: function () { /*...*/ }
    })
});
state obj, 'abstract',
  Alive: state 'default initial mutable',
    update: -> # ...
  Dead: state 'final',
    update: -> # ...
SEE ALSO

Attributes

mutable

By default, states are weakly immutable — their data, methods, guards, substates, and transitions cannot be altered once the state has been constructed. Applying the mutable attribute lifts the restriction of immutability, allowing the use of methods such as mutate, addMethod, addSubstate, etc., which can be used to alter the contents of the state.

NOTES

The mutable attribute is inherited from both superstates and protostates, unless any also bear the immutable attribute.

EXAMPLE
function Mover () {}
state( Mover.prototype, {
    Moving: state
});

Mover.prototype.state().mutate({
    aMethod: function () {},
    Stationary: state
});

Mover.prototype.state('Stationary');  // >>> undefined            [1]

var mover = new Mover;
state( mover, 'mutable' );
mover.state().mutate({
    aMethod: function () {},
    Stationary: state
});

mover.state('-> Stationary');
mover.state();                        // >>> State 'Stationary'
mover.state().isMutable();            // >>> true            [2], [3]

mover.state('-> Moving');
mover.state();                        // >>> State 'Moving'
mover.state().isMutable();            // >>> true                 [3]
class Mover
  state @::,
    Moving: state

Mover::state().mutate
  aMethod: ->
  Stationary: state

Mover::state 'Stationary'     # >>> undefined                   [1]

mover = new Mover
state mover, 'mutable'
mover.state().mutate
  aMethod: ->
  Stationary: state

mover.state '-> Stationary'
mover.state()                 # >>> State 'Stationary'
mover.state().isMutable()     # >>> true                   [2], [3]

mover.state '-> Moving'
mover.state()                 # >>> State 'Moving'
mover.state().isMutable()     # >>> true                        [3]
  1. Without a mutable attribute, the states of Mover.prototype are weakly immutable, so their content cannot be altered, and the attempt to call mutate has no effect.

  2. Because the mover instance’s root state was declared mutable, content can be added later to that state or to any state that inherits from it.

  3. Substates, including virtual states and any state added later, automatically inherit the mutable attribute assigned to their superstates.

SEE ALSO

isMutable, mutate (method), mutate (event)

Mutability attributes

finite

Declaring a state finite guarantees its hierarchical structure by disabling its addSubstate and removeSubstate methods after the state has been constructed.

NOTES

The finite attribute is inherited from both superstates and protostates, and is imposed with higher precedence than mutable.

EXAMPLE
function Mover () {}
state( Mover.prototype, 'finite', {
    Stationary: state,
    Moving: {
        Walking: state
    }
});

var mover = new Mover;
state( mover, {
    Moving: {
        Running: state('mutable')
    }
});

mover.state('Moving').isFinite();                // >>> true      [1]
mover.state('Running').isFinite();               // >>> true      [1]

mover.state('Running').addSubstate('Sprinting'); // >>> undefined [2]
class Mover
  state @::, 'finite',
    Stationary: state
    Moving:
      Walking: state

mover = new Mover
state mover,
  Moving:
    Running: state 'mutable'

mover.state('Moving').isFinite()                # >>> true      [1]
mover.state('Running').isFinite()               # >>> true      [1]

mover.state('Running').addSubstate 'Sprinting'  # >>> undefined [2]
  1. The mover instance may define new states of its own, but its states will also inherit the finite attribute from Mover.prototype.

  2. Even though mover’s Running state is declared mutable, it is subject to the restrictions of its inherited finite attribute, since finite is more powerful than mutable. Therefore an attempt to add a substate later will fail.

SEE ALSO

isFinite

Mutability attributes

immutable

Adding immutable makes a state strongly immutable, whereupon immutability is permanent and absolute: immutable contradicts and overrules mutable, and implies finite, irrespective of whether any of the attributes are literal or inherited.

NOTES

The immutable attribute is inherited from both superstates and protostates, and has top precedence over mutable and finite.

An inheriting owner object may still extend the state implementation of its prototype with states that are new, or that extend protostates, but any of these that inherit from an immutable state will implicitly also bear the immutable attribute themselves.

EXAMPLE
function Mover () {}
state( Mover.prototype, 'immutable', {
    Moving: state
});

var mover = new Mover;
state( mover, 'mutable', {                  //                [1]
    Stationary: state                       //                [2]
});

mover.state('').isMutable();                // >>> false      [1]
mover.state('Stationary').isMutable();      // >>> false      [2]

mover.state().addMethod( 'thisWontWork', function () {
    // ...
});                                         // >>> undefined  [3]
class Mover
  state @::, 'immutable',
    Moving: state

mover = new Mover
state mover, 'mutable',                     #                 [1]
  Stationary: state                         #                 [2]

mover.state('').isMutable()                 # >>> false       [1]
mover.state('Stationary').isMutable()       # >>> false       [2]

mover.state().addMethod 'thisWontWork', ->  # >>> undefined   [3]
  1. The mover instance was declared mutable, but its prototype is immutable, so applying mutable on the inheriting root state here is superfluous: mutable is negated and immutable is inherited.

  2. The call to state does allow mover to extend its prototype’s immutable state, although the new Stationary state will also inherit immutable.

  3. Attempts to alter the state’s contents after it has been constructed will have no effect.

SEE ALSO

isImmutable

Mutability attributes

abstract

A state that is abstract cannot itself be current. Consequently a transition that targets an abstract state will be forcibly redirected to the appropriate concrete descendant of the abstract state.

The redirection target of an abstract state is determined by seeking its first-iterated substate marked default. If no default substate exists, the first substate is targeted. If the redirection target is itself abstract, then the process is repeated until a concrete descendant is found. If an abstract state has no concrete descendants, currency is directed as deep as possible via the first substate at each level.

As object keys are not strictly ordered, it is a best practice to ensure that, whether literally or via inheritance, exactly one substate of an abstract state is always named as its default.

NOTES

The abstract attribute is inherited from protostates.

EXAMPLE
function Mover () {}
state( Mover.prototype, 'abstract', {
    Moving: state( 'abstract', {
        Walking: state,
        Running: state
    })
});

var mover = new Mover;

mover.state('->');
mover.state();             // >>> State 'Walking'

mover.state('-> Moving');
mover.state();             // >>> State 'Walking'
class Mover
  state @::, 'abstract',
    Moving: state 'abstract',
      Walking: state
      Running: state

mover = new Mover

mover.state '->'
mover.state()            # >>> State 'Walking'

mover.state '-> Moving'
mover.state()            # >>> State 'Walking'
SEE ALSO

isAbstract

Abstraction attributes

concrete

Including the concrete attribute will override the abstract attribute that would otherwise have been inherited from an abstract protostate.

Any state that is not abstract is by definition concrete, even if not literally attributed as such, and will return true in a call to isConcrete.

NOTES

The concrete attribute is inherited from protostates.

EXAMPLE
function Mover () {}
state( Mover.prototype, 'abstract', {
    Moving: state( 'abstract', {
        Walking: state
    })
});

var mover = new Mover;
state( mover, {
    Moving: state('concrete')
});

mover.state('-> Moving');
mover.state();             // >>> State 'Moving'
class Mover
  state @::, 'abstract',
    Moving: state 'abstract',
      Walking: state

mover = new Mover
state mover,
  Moving: state 'concrete'

mover.state '-> Moving'
mover.state()            # >>> State 'Moving'
SEE ALSO

isConcrete

Abstraction attributes

default

Marking a state default designates it as the intended redirection target for any transition that has targeted its abstract superstate.

NOTES

The default attribute is inherited from protostates.

EXAMPLE
function Mover () {}
state( Mover.prototype, 'abstract', {
    Stationary: state,
    Moving: state( 'default abstract', {
        Walking: state,
        Running: state('default')
    })
});

var mover = new Mover;
mover.state('->');         // >>> State 'Running'
mover.state('-> Moving');  // >>> State 'Running'
class Mover
  state @::, 'abstract',
    Stationary: state
    Moving: state 'default abstract',
      Walking: state
      Running: state 'default'

mover = new Mover

mover.state '->'
mover.state()            # >>> State 'Running'

mover.state '-> Moving'
mover.state()            # >>> State 'Running'
SEE ALSO

isDefault, defaultSubstate

Abstraction attributes State::defaultSubstate

initial

Marking a state initial specifies which state is to be assumed immediately following the state() application. No transition or any enter or arrive events result from this initialization.

For an object that inherits its entire state implementation from its prototype, the inheritor’s initial state will be set to the prototype’s current state.

NOTES

The initial attribute is inherited from protostates.

EXAMPLE
function Mover () {}
state( Mover.prototype, {
    Stationary: state('initial'),
    Moving: state
});

var mover1 = new Mover;
mover1.state();                      // >>> State 'Stationary'

Mover.prototype.state('-> Moving');
var mover2 = new Mover;
mover2.state();                      // >>> State 'Moving'

var mover3 = new Mover;
state( mover3, {
    Stationary: state,
    Moving: {
        Walking: state,
        Running: state('initial')
    }
});                                  // >>> State 'Running'
class Mover
  state @::
    Stationary: state 'initial'
    Moving: state

mover1 = new Mover
mover1.state()                # >>> State 'Stationary'

Mover::state '-> Moving'
mover2 = new Mover
mover2.state()                # >>> State 'Moving'

mover3 = new Mover
state mover3,
  Stationary: state
  Moving:
    Walking: state
    Running: state 'initial'
mover3.state()                # >>> State 'Running'
SEE ALSO

isInitial, initialSubstate

Destination attributes State::initialSubstate

conclusive

Once a conclusive state is entered, it cannot be exited, although transitions may still freely traverse within its substates.

NOTES

The conclusive attribute is inherited from protostates.

EXAMPLE
function Mover () {}
state( Mover.prototype, {
    Stationary: state,
    Moving: state( 'conclusive', {
        Walking: state,
        Running: state
    })
});

var mover = new Mover;

mover.state('-> Stationary');
mover.state();                 // >>> State 'Stationary'

mover.state('-> Walking');
mover.state();                 // >>> State 'Walking'

mover.state('-> Stationary');
mover.state();                 // >>> State 'Walking'

mover.state('-> Running');
mover.state();                 // >>> State 'Running'
class Mover
  state @::,
    Stationary: state
    Moving: state 'conclusive',
      Walking: state
      Running: state

mover = new Mover

mover.state '-> Stationary'
mover.state()                # >>> State 'Stationary'

mover.state '-> Walking'
mover.state()                # >>> State 'Walking'

mover.state '-> Stationary'
mover.state()                # >>> State 'Walking'

mover.state '-> Running'
mover.state()                # >>> State 'Running'
SEE ALSO

isConclusive

Destination attributes

final

Once an object’s currency arrives at a final state, no further transitions are allowed.

A final state is not necessarily conclusive: a transition may enter a final state on its way to a descendant, and still exit from it later, so long as it never arrives at the final state.

NOTES

The final attribute is inherited from protostates.

EXAMPLE
function Mover () {}
state( Mover.prototype, {
    Stationary: state,
    Moving: state( 'final', {
        Walking: state
    })
});

var mover = new Mover;

mover.state('-> Walking');
mover.state();                 // >>> State 'Walking'

mover.state('-> Stationary');
mover.state();                 // >>> State 'Stationary'

mover.state('-> Moving');
mover.state();                 // >>> State 'Moving'

mover.state('-> Walking');
mover.state();                 // >>> State 'Moving'

mover.state('-> Stationary');
mover.state();                 // >>> State 'Moving'
class Mover
  state @::,
    Stationary: state
    Moving: state 'final',
      Walking: state

mover = new Mover

mover.state '-> Walking'
mover.state()                  # >>> State 'Walking'

mover.state '-> Stationary'
mover.state()                  # >>> State 'Stationary'

mover.state '-> Moving'
mover.state()                  # >>> State 'Moving'

mover.state '-> Walking'
mover.state()                  # >>> State 'Moving'

mover.state '-> Stationary'
mover.state()                  # >>> State 'Moving'
SEE ALSO

isFinal

Destination attributes

Methods

realize

Transforms this virtual state into a “real” state that can bear content of its own.

SYNTAX
this.realize()
this.realize( expression )
PARAMETERS
  • expressionopt : ( object | StateExpression )
RETURNS

this

EXAMPLES

If this is already real instead of virtual, then calling realize has no effect.

function Mover () {}
state( Mover.prototype, 'mutable', {
    Moving: {
        Running: state
    }
});

var mover = new Mover;
mover.state('-> Moving');
var s = mover.state();     // >>> State 'Moving'
s.isVirtual();             // >>> true
s.realize();
s.isVirtual();             // >>> false
class Mover
  state @::, 'mutable',
    Moving:
      Running: state

mover = new Mover
mover.state '-> Moving'
s = mover.state()               # >>> State 'Moving'
s.isVirtual()                   # >>> true
s.realize()
s.isVirtual()                   # >>> false

If this is both virtual and mutable, then calling any of its add* methods necessarily uses realize to transform into a real state before content is added.

mover.state('-> Running');
s = mover.state();                 // >>> State 'Running'
s.isVirtual();                     // >>> true
s.addMethod( 'move', function () { return "Boing"; } );
s.isVirtual();                     // >>> false
mover.state '-> Running'
s = mover.state()               # >>> State 'Running'
s.isVirtual()                   # >>> true
s.addMethod 'move', -> "Boing"
s.isVirtual()                   # >>> false
SEE ALSO

Protostates and epistates Virtual epistates State realize State::realize

destroy

Attempts to cleanly destroy this state and all of its descendant states.

SYNTAX
this.destroy()
RETURNS

true if this state is successfully destroyed, or false otherwise.

NOTES

A destroy event is issued by each state as it is destroyed.

If the root state is destroyed, the owner is given back any methods it bore prior to its state implementation.

SEE ALSO

State::destroy

express

Produces an object containing an expression of the contents of this state, such as would be sufficient to create a new State structurally identical to this.

SYNTAX
this.express()
this.express( typed )
PARAMETERS
  • typed = false : boolean
RETURNS

The generated plain-object, or equivalent StateExpression if typed is true.

EXAMPLE
var mover = {};
state( mover, 'mutable abstract', {
    Stationary: state( 'initial default', {
        move: function () { return "!"; }
    }),
    Moving: {
        Walking: {
            move: function () { return "step step"; }
        },
        Running: {
            move: function () { return "boing boing"; },
            Sprinting: state
        }
    }
});

// Add a 'report' method to each of the states.
O.forEach( mover.state('').substates( true ), function ( substate ) {
    substate.addMethod( 'report', function () {
        console.log( "I'm in state '" + this.name() + "'" );
    });
});
mover.report();  // log <<< "I'm in state 'Stationary'"

// Express the root state.
var expression = mover.state('').express();  // >>> Object

// Use `expression` to clone the state implementation of `mover` into
// some other unrelated object.
var other = {};
state( other, expression );
other.report();  // log <<< "I'm in state 'Stationary'"
mover = {}
state mover, 'mutable abstract',
  Stationary: state 'initial default',
    move: -> "!"
  Moving:
    Walking:
      move: -> "step step"
    Running:
      move: -> "boing boing"
      Sprinting: state

# Add a 'report' method to each of the states.
for substate in mover.state('').substates true
  substate.addMethod 'report', ->
    console.log "I'm in state '#{ @name() }'"

mover.report()  # log <<< "I'm in state 'Stationary'"

# Express the root state.
expression = mover.state('').express()  # >>> Object

# Use `expression` to clone the state implementation of `mover` into
# some other unrelated object.
other = {}
state other, expression
other.report()  # log <<< "I'm in state 'Stationary'"
SEE ALSO

Expressions State::express

mutate

Transactionally mutates this state by adding, updating, or removing items as implied by the contents of expression.

SYNTAX
this.mutate( expression )
PARAMETERS
  • expression : ( StateExpression | object )
RETURNS

this

NOTES

Property removal is indicated with a value equal to the unique O.NIL reference.

If the transaction causes a mutation, this emits a mutate event.

EXAMPLE
var NIL = state.NIL;

var mover = {};
state( mover, 'mutable', {
    mutate: function () {
        console.log( "I feel different" );
    },
    Stationary: state,
    Evil: state
});

// Update `Stationary`, create `Moving`, and delete `Evil`
mover.state('').mutate({
    Stationary: {
        move: function () { return "!"; }
    },
    Moving: {
        Walking: state,
        Running: state
    },
    Evil: NIL
});
// log <<< "I feel different"
{NIL} = state

mover = {}
state mover, 'mutable',
  mutate: -> console.log "I feel different"
  Stationary: state
  Evil: state

# Update `Stationary`, create `Moving`, and delete `Evil`
mover.state('').mutate
  Stationary: move: -> "!"
  Moving:
    Walking: state
    Running: state
  Evil: NIL
# log <<< "I feel different"
SEE ALSO

Mutation events State::mutate

substate

Identifies a named substate of this.

SYNTAX
this.substate( stateName, via )
PARAMETERS
  • stateName : string
  • via = VIA_PROTO : boolean
RETURNS

The substate of this state named stateName. If no such substate exists locally within this, and the VIA_PROTO bit of via is set, then the nearest identically named substate held on a protostate will be returned.

SEE ALSO

State::substate

substates

Generates a collection of the immediate substates of this.

SYNTAX
this.substates( virtual )
PARAMETERS
  • virtual = false : boolean
RETURNS

An Array of this state’s substates.

NOTES

If virtual is true, the returned array may include any active virtual states held by an owner object that is inheriting currency from a prototype.

SEE ALSO

State::substates

descendants

Generates a depth-first flattened collection of this state’s substates, their respective substates, etc.

SYNTAX
this.descendants( virtual )
PARAMETERS
  • virtual = false : boolean
RETURNS

An Array that includes all of this state’s descendant states.

NOTES

If virtual is true, the returned array may include any active virtual states held by an owner object that is inheriting currency from a prototype.

SEE ALSO

State::descendants

addSubstate

Creates a State based on the provided stateExpression, adds it as a substate of this state.

SYNTAX
this.addSubstate( stateName, stateExpression )
PARAMETERS
  • stateName : string
  • stateExpression : ( StateExpression | object | State )
RETURNS

The new State.

NOTES

If a substate with the same stateName already exists, it is first destroyed and then replaced.

SEE ALSO

State::addSubstate

removeSubstate

Removes the substate named by stateName from this state, if possible.

SYNTAX
this.removeSubstate( stateName )
PARAMETERS
  • stateName : string
RETURNS

The removed State.

NOTES

If the owner object is in the midst of a transition involving the state targeted for removal, then the removal will fail, returning false.

SEE ALSO

State::removeSubstate

derivation

Describes the superstate chain of this as an array.

SYNTAX
this.derivation( byName )
PARAMETERS
  • byName = false : boolean
RETURNS

An Array containing each State from the root state to this state, starting with the immediate substate from the root.

If byName is true, the returned Array contains the string names of each state, rather than the States themselves.

EXAMPLE
var mover = {};
state( mover, {
    Moving: {
        Running: {
            Sprinting: state
        }
    }
});

var s = mover.state('Sprinting')
s.derivation();
// >>> [ State 'Moving', State 'Running', State 'Sprinting' ]
s.derivation( true );
// >>> [ "Moving", "Running", "Sprinting" ]
mover = {}
state mover,
  Moving:
    Running:
      Sprinting: state

s = mover.state 'Sprinting'
s.derivation()
# >>> [ State 'Moving', State 'Running', State 'Sprinting' ]
s.derivation true
# >>> [ "Moving", "Running", "Sprinting" ]
SEE ALSO

State::derivation

path

Describes the superstate chain of this as a dot-delimited string.

SYNTAX
this.path()
RETURNS

A string that matches the absolute selector referencing this state.

EXAMPLE
var mover = {};
state( mover, {
    Moving: {
        Running: {
            Sprinting: state
        }
    }
});

mover.state('Sprinting').path();  // >>> "Moving.Running.Sprinting"
mover = {}
state mover,
  Moving:
    Running:
      Sprinting: state

mover.state('Sprinting').path()  # >>> "Moving.Running.Sprinting"
SEE ALSO

State::path

depth

Quantifies the height of the superstate chain of this.

SYNTAX
this.depth()
RETURNS

The number of superstates separating this state from its root state.

EXAMPLE
var mover = {};
state( mover, {
    Moving: {
        Running: state
    }
});

mover.state('Running').depth();  // >>> 2
mover.state('').depth();         // >>> 0
mover = {}
state mover,
  Moving:
    Running: state

mover.state('Running').depth()  # >>> 2
mover.state('').depth()         # >>> 0
SEE ALSO

State::depth

common

Establishes the hierarchical relation between this and another State.

SYNTAX
this.common( other )
PARAMETERS
  • other : ( State | string )
RETURNS

The State that is the nearest common ancestor of both this state and the provided other state.

EXAMPLE
var mover = {};
state( mover, {
    Stationary: state
    Moving: {
        Walking: state,
        Running: {
            Sprinting: state
        }
    }
});

mover.state('Sprinting').common('Walking');  // >>> State 'Moving'
mover = {}
state mover,
  Stationary: state
  Moving:
    Walking: state
    Running:
      Sprinting: state

mover.state('Sprinting').common 'Walking'  # >>> State 'Moving'
SEE ALSO

State::common

is

Asserts identity.

SYNTAX
this.is( other )
PARAMETERS
  • other : ( State | string )
RETURNS

A boolean indicating whether this state is the provided other state.

EXAMPLE
var mover = {};
state( mover, {
    Moving: {
        Running: {
            Sprinting: state
        }
    }
});

var s = mover.state('Sprinting');  // >>> State 'Sprinting'
s.is('Moving.Running.Sprinting');  // >>> true
mover = {}
state mover,
  Moving:
    Running:
      Sprinting: state

s = mover.state 'Sprinting'      # >>> State 'Sprinting'
s.is 'Moving.Running.Sprinting'  # >>> true
SEE ALSO

State::is

isIn

Asserts descendant familiarity.

SYNTAX
this.isIn( other )
PARAMETERS
  • other : ( State | string )
RETURNS

A boolean indicating whether this state is or is a substate of the provided other state.

EXAMPLE
var mover = {};
state( mover, {
    Moving: {
        Running: {
            Sprinting: state
        }
    }
});

var s = mover.state('Sprinting');  // >>> State 'Sprinting'
s.isIn('Running');                 // >>> true
mover = {}
state mover,
  Moving:
    Running:
      Sprinting: state

s = mover.state 'Sprinting'  # >>> State 'Sprinting'
s.isIn 'Running'             # >>> true
SEE ALSO

State::isIn

hasSubstate

Asserts ancestral familiarity.

SYNTAX
this.hasSubstate( other )
PARAMETERS
  • other : ( State | string )
RETURNS

A boolean indicating whether this state is or is a superstate of the provided other state.

EXAMPLE
var mover = {};
state( mover, {
    Moving: {
        Running: {
            Sprinting: state
        }
    }
});

var s = mover.state('Moving');  // >>> State 'Moving'
s.has('Sprinting');             // >>> true
s.has('Moving');                // >>> true
mover = {}
state mover,
  Moving:
    Running:
      Sprinting: state

s = mover.state 'Moving'  # >>> State 'Moving'
s.has 'Sprinting'         # >>> true
s.has 'Moving'            # >>> true
SEE ALSO

State::hasSubstate

isSuperstateOf

Asserts hierarchical ancestry.

SYNTAX
this.isSuperstateOf( other )
PARAMETERS
  • other : ( State | string )
RETURNS

A boolean indicating whether this state is a superstate of the provided other state.

EXAMPLE
var mover = {};
state( mover, {
    Moving: {
        Running: {
            Sprinting: state
        }
    }
});

var s = mover.state('Moving');  // State 'Moving'
s.isSuperstateOf('Sprinting');  // >>> true
s.isSuperstateOf('Moving');     // >>> false
mover = {}
state mover,
  Moving:
    Running:
      Sprinting: state

s = mover.state 'Moving'      # >>> State 'Moving'
s.isSuperstateOf 'Sprinting'  # >>> true
s.isSuperstateOf 'Moving'     # >>> false
SEE ALSO

superstate

State::isSuperstateOf

defaultSubstate

Resolves the proper concretion for an abstract state.

SYNTAX
this.defaultSubstate( via )
PARAMETERS
  • via = VIA_PROTO : number
RETURNS

The State that is this state’s first substate bearing the default attribute, or just the first substate if none are found.

EXAMPLE
var mover = {};
state( mover, 'abstract', {
    Stationary: state,
    Moving: state( 'default abstract', {
        Walking: state,
        Running: {
            Sprinting: state('initial')
        }
    })
});

mover.state('').defaultSubstate();        // >>> State 'Moving'   [1]
mover.state('Moving').defaultSubstate();  // >>> State 'Walking'  [2]

mover.state();                            // >>> State 'Sprinting'
mover.state('->');
mover.state();                            // >>> State 'Walking'  [3]
mover = {}
state mover, 'abstract',
  Stationary: state
  Moving: state 'default abstract',
    Walking: state
    Running:
      Sprinting: state 'initial'

mover.state('').defaultSubstate()        # >>> State 'Moving'    [1]
mover.state('Moving').defaultSubstate()  # >>> State 'Walking'   [2]

mover.state()                            # >>> State 'Sprinting'
mover.state '->'
mover.state()                            # >>> State 'Walking'   [3]
  1. Moving is explicitly marked default.

  2. Since Moving, which is itself abstract, has no descendant states marked default, its first substate Walking serves as its default state.

  3. A transition targeting the root state will fall through to Walking, since both the root and its default state Moving are abstract.

SEE ALSO

State::defaultSubstate

initialSubstate

SYNTAX
this.initialSubstate()
RETURNS

The State that is this state’s most deeply nested state bearing the initial attribute, by way of its greatest initial descendant state.

SEE ALSO

State::initialSubstate

getProtostate

Performs the lookup to identify the State analogous to this that is owned by a prototype of the owner.

SYNTAX
this.getProtostate()
RETURNS

The protostate of this: that State which both has a derivation path identical to the path of this, and whose owner is the nearest possible prototype of the owner of this.

Returns undefined if no protostate exists anywhere in the owner’s prototype chain.

EXAMPLE
function Mover () {}
state( Mover.prototype, {
    Stationary: state,
    Moving: {
        Walking: state,
        Running: {
            Sprinting: state('initial')
        }
    }
});

var mover, protostate, epistate;
mover = new Mover;
protostate = Mover.prototype.state();     // >>> State 'Sprinting'
epistate = mover.state();                 // >>> State 'Sprinting'

protostate === epistate;                  // >>> false
protostate === epistate.getProtostate();  // >>> true
class Mover
  state @::
    Stationary: state
    Moving:
      Walking: state
      Running:
        Sprinting: state 'initial'

mover = new Mover
protostate = Mover::state()             # >>> State 'Sprinting'
epistate = mover.state()                # >>> State 'Sprinting'

protostate is epistate                  # >>> false
protostate is epistate.getProtostate()  # >>> true
SEE ALSO

Protostates State::getProtostate

isProtostateOf

Asserts prototypal ancestry of an other State relative to this; i.e., whether an other State has an identical path to this and the owner of other is a prototype of the owner of this.

SYNTAX
this.isProtostateOf( other )
PARAMETERS
  • other : ( State | string )
RETURNS

A boolean indicating whether this state is a protostate of the provided other state.

EXAMPLE
function Animal () {}
state( Animal.prototype, 'abstract', {
    Alive: state('default'),
    Dead: state
});

O.inherit( Bird, Animal );
function Bird () {}


var canary, a, b, c;

canary = new Bird;                   // >>> Bird

a = Animal.prototype.state();        // >>> State 'Alive'
b = Bird.prototype.state();          // >>> State 'Alive'
c = canary.state();                  // >>> State 'Alive'
a.isProtostateOf( c );               // >>> true
b.isProtostateOf( c );               // >>> true                 [1]
a === b;                             // >>> false                [1]

canary.state('-> Dead');
canary.state();                      // >>> State 'Dead'

a = Animal.prototype.state('Dead');  // >>> State 'Dead'
b = Bird.prototype.state('Dead');    // >>> State 'Dead'
c = canary.state();                  // >>> State 'Dead'
a.isProtostateOf( c );               // >>> true
b.isProtostateOf( c );               // >>> false                [2]
a === b;                             // >>> true                 [2]
class Animal
  state @::, 'abstract',
    Alive: state 'default'
    Dead: state

class Bird extends Animal

canary = new Bird         # >>> Bird

a = Animal::state()       # >>> State 'Alive'
b = Bird::state()         # >>> State 'Alive'
c = canary.state()        # >>> State 'Alive'
a.isProtostateOf c        # >>> true
b.isProtostateOf c        # >>> true                             [1]
a is b                    # >>> false                            [1]

canary.state '-> Dead'
canary.state()            # >>> State 'Dead'

a = Animal::state 'Dead'  # >>> State 'Dead'
b = Bird::state 'Dead'    # >>> State 'Dead'
c = canary.state()        # >>> State 'Dead'
a.isProtostateOf c        # >>> true
b.isProtostateOf c        # >>> false                            [2]
a is b                    # >>> true                             [2]
SEE ALSO

protostate

Protostates State::isProtostateOf

query

Matches a selector string with the state or states it represents in the context of this state.

SYNTAX
this.query( selector )
this.query( selector, against )
this.query( selector, against, via )
this.query( selector, via )
PARAMETERS
  • selector : string
  • againstopt : State
  • via = VIA_ALL : number

The via parameter is a bit-field integer comprised of one or more of the TRAVERSAL_FLAGS constants: [VIA_SUB, VIA_SUPER, VIA_PROTO].

By default via is VIA_ALL (~0), which implies each of the flags’ bits are set, and consequently that the query operation will be recursed over the substates, superstates, and protostates, in order, of this. Providing a via argument that zeroes any of the VIA_SUB, VIA_SUPER, or VIA_PROTO bits will disable recursion through the substates, superstates, or protostates, respectively, of this.

RETURNS

The nearest matching State, or if a non-specific selector is provided, an Array containing the set of matched states. If a state to be tested against is provided, then a boolean is returned, indicating whether against is the matched state itself or is included in the matching set.

NOTES

Calling an owner object’s accessor method with a selector string invokes query on the owner’s current state.

SEE ALSO

Getting started Selectors State::query

$

Convenience method that mimics the behavior of the owner’s accessor method.

SYNTAX
this.$( selector )
PARAMETERS
  • selector : string
RETURNS

If the first argument is a transition arrow selector string, the call is aliased to change. If passed a plain selector string, the call is aliased to query.

EXAMPLES
this.$('-> Awake')
@$ '-> Awake'

Aliases to change, instigating a transition to the Awake state.

this.$('Awake')
@$ 'Awake'

Aliases to query, returning the State named 'Awake'.

current

Returns the current State of this state’s owner.

SYNTAX
this.current()
RETURNS

State.

isCurrent

Indicates whether this state is the owner’s current state.

SYNTAX
this.isCurrent()
RETURNS

Boolean.

isActive

Indicates whether this state or one of its substates is the owner’s current state.

SYNTAX
this.isActive()
RETURNS

Boolean.

change

Attempts to execute a state transition.

ALIASES

go, be

SYNTAX
this.change( target )
this.change( target, options )
PARAMETERS
  • target : ( State | string )
  • optionsopt : object

The target parameter may be either a State object within the purview of this controller, or a string that resolves to a likewise targetable State when evaluated from the context of the most recently current state.

The options parameter is an optional map that may include:

  • args : Array — arguments to be passed to a transition’s action function.
  • success : function — callback to be executed upon successful completion of the transition.
  • failure : function — callback to be executed if the transition attempt is blocked by a guard.
DISCUSSION

Handles asynchronous transitions, generation of appropriate events, and construction of any necessary temporary virtual states. Respects guards supplied in both the origin and target states.

isVirtual

Indicates whether this state bears the virtual attribute.

SYNTAX
this.isVirtual()
RETURNS

Boolean.

DISCUSSION

A virtual state is a lightweight inheritor of a protostate located higher in the owner object’s prototype chain. Notably, as virtual states are created automatically, no modifier keyword exists for the virtual attribute.

EXAMPLE
function Mover () {}
state( Mover.prototype, {
    Stationary: state('initial'),
    Moving: state
});

var mover = new Mover;

mover.state();              // >>> State 'Stationary'
mover.state().isVirtual();  // >>> true                           [1]

mover.state('->');
mover.state();              // >>> State ''
mover.state().isVirtual();  // >>> false                          [2]
class Mover
  state @::,
    Stationary: state 'initial'
    Moving: state

var mover = new Mover

mover.state()               # >>> State 'Stationary'
mover.state().isVirtual()   # >>> true                          [1]

mover.state '->'
mover.state()               # >>> State ''
mover.state().isVirtual()   # >>> false                         [2]
  1. The mover instance, which inherits its stateful implementation from Mover.prototype, does not have a real Stationary state of its own, so a virtual Stationary state is created automatically and adopted as mover’s initial state.

  2. Root states are never virtualized. Even an object that inherits all statefulness from its prototypes is given a real root state.

SEE ALSO

Protostates

isMutable

Indicates whether this state bears the mutable attribute.

SYNTAX
this.isMutable()
RETURNS

Boolean.

DISCUSSION

By default, states are weakly immutable; i.e., once a State has been constructed, its declared data, methods, guards, substates, and transitions cannot be altered. By including the mutable attribute in the state’s expression, this restriction is lifted. Mutability is also inherited from any of a state’s superstates or protostates.

SEE ALSO

mutable

isFinite

Indicates whether this state bears the finite attribute.

SYNTAX
this.isFinite()
RETURNS

Boolean.

DISCUSSION

If a state is declared finite, no substates or descendant states may be added, nor may any be removed without also destroying the state itself.

SEE ALSO

finite

isImmutable

Indicates whether this state bears the immutable attribute.

SYNTAX
this.isImmutable()
RETURNS

Boolean.

DISCUSSION

A literal or inherited immutable attribute causes a state to become strongly immutable, wherein it guarantees immutability absolutely, throughout all inheriting states. The immutable attribute also implies finite, and contradicts and overrides any literal or inherited mutable attribute.

SEE ALSO

immutable

isAbstract

Indicates whether this state is abstract.

SYNTAX
this.isAbstract()
RETURNS

Boolean.

DISCUSSION

An abstract state is used only as a source of inheritance, and cannot itself be current. A transition that directly targets an abstract state will be automatically redirected to one of its substates.

SEE ALSO

abstract

isConcrete

Indicates whether this state is concrete.

SYNTAX
this.isConcrete()
RETURNS

Boolean.

DISCUSSION

All non-abstract states are concrete. Marking a state with the concrete attribute in a state expression will override any abstract attribute, particularly such as would otherwise be inherited from a protostate.

SEE ALSO

concrete

isDefault

Indicates whether this state bears the default attribute.

SYNTAX
this.isDefault()
RETURNS

Boolean.

DISCUSSION

Marking a state default designates it as the specific redirection target for any transition that targets its abstract superstate.

SEE ALSO

default, defaultSubstate

isInitial

Indicates whether this state bears the initial attribute.

SYNTAX
this.isInitial()
RETURNS

Boolean.

DISCUSSION

Marking a state initial specifies which state a newly stateful object should assume.

Objects inheriting from a stateful prototype will have their initial state set to the prototype’s current state.

SEE ALSO

initial, initialSubstate

isConclusive

Indicates whether this state bears the conclusive attribute.

SYNTAX
this.isConclusive()
RETURNS

Boolean.

DISCUSSION

Once a state marked conclusive is entered, it cannot be exited, although transitions may still freely traverse within its substates.

SEE ALSO

conclusive

isFinal

Indicates whether this state bears the final attribute.

SYNTAX
this.isFinal()
RETURNS

Boolean.

DISCUSSION

Once a state marked final is entered, no further outbound transitions within its local region are allowed.

SEE ALSO

final

data (read)

Reads a composite of the data assigned to this state.

SYNTAX
this.data()
this.data( via )
PARAMETERS
  • via = VIA_ALL : number
RETURNS

An object clone of the data attached to this state, including any data inherited from protostates and superstates, unless specified otherwise by zeroing the VIA_SUPER and VIA_PROTO bits of via.

SEE ALSO

State::data

data (write)

Adds, updates, and/or removes data properties on this state.

SYNTAX
this.data( edit )
PARAMETERS
  • edit : object
RETURNS

this.

NOTES

For any keys in edit whose values are set to the O.NIL directive, the matching properties are deleted from this state’s data.

If the operation results in a change to this state’s data, a mutate event is emitted.

SEE ALSO

State::data

has

Determines whether a data property with the given key exists on this state, or is inherited from a protostate or superstate.

SYNTAX
this.has( key )
this.has( key, via )
PARAMETERS
  • key : string
  • via = VIA_ALL : number
NOTES

Supports long.key.path lookups for deeply nested properties.

SEE ALSO

State::has

get

Reads a data item on this state.

SYNTAX
this.get( key )
this.get( key, via )
PARAMETERS
  • key : string
  • via = VIA_ALL : number
RETURNS

The value of the data property with the given key on this state, or one inherited from the nearest protostate, or the nearest superstate.

NOTES

Supports long.key.path lookups for deeply nested properties. Returns undefined if key cannot be resolved.

State::get

let

Writes a data item on this state.

SYNTAX
this.let( key, value )
PARAMETERS
  • key : string
  • value : var
RETURNS

If successful, the assigned value.

NOTES

Creates a new data property or updates an existing data property on this state.

Succeeds only if this state is mutable.

Supports long.key.path assignments to deeply nested properties.

SEE ALSO

State::let

set

Writes or updates an existing data item on either this state or a superstate.

SYNTAX
this.set( key, value )
PARAMETERS
  • key : string
  • value : var
RETURNS

The assigned value.

DISCUSSION

If the property is inherited from a mutable superstate, then the property is updated in place, equivalent to calling let on that superstate. If the data property does not yet exist in the superstate chain, it is created on this. Properties inherited from protostates are not affected.

NOTES

Supports long.key.path assignments to deeply nested properties.

SEE ALSO

State::set

delete

Deletes an existing data property on this state.

SYNTAX
this.delete( key )
PARAMETERS
  • key : string
RETURNS

Boolean true if the deletion was successful or unnecessary, or false otherwise, in the same manner as the native delete operator.

NOTES

Supports long.key.path lookups for deeply nested properties.

SEE ALSO

State::delete

method

SYNTAX
this.method( methodName )
this.method( methodName, via )
this.method( methodName, via, out )
PARAMETERS
  • methodName : string
  • via = VIA_ALL : number
  • outopt : object
RETURNS

The function that is the method held on this state whose name is methodName.

DISCUSSION

If the named method does not exist on this state, then it will be inherited, in order, first from protostates of this (if the VIA_PROTO bit of via is set), and if no such method exists there, then from superstates of this (if the VIA_SUPER bit of via is set).

If an out object is supplied, then the returned function is attached to out.method, and the State context to which the method will be bound when invoked with this.apply or this.call is attached to out.context.

SEE ALSO

State::method

methodNames

SYNTAX
this.methodNames()
RETURNS

An Array of names of methods defined locally on this state.

SEE ALSO

State::methodNames

addMethod

Adds fn as a method named methodName to this state, which will be callable directly from the owner, but with its context bound to this.

SYNTAX
this.addMethod( methodName, fn )
PARAMETERS
  • methodName : string
  • fn : function
RETURNS

fn.

SEE ALSO

State::addMethod

removeMethod

Dissociates the method named methodName from this state and returns its function.

SYNTAX
this.removeMethod( methodName )
PARAMETERS
  • methodName : string
SEE ALSO

State::removeMethod

hasMethod

Indicates whether this state possesses or inherits a method named methodName.

SYNTAX
this.hasMethod( methodName )
PARAMETERS
  • methodName : string
RETURNS

Boolean.

SEE ALSO

State::hasMethod

hasOwnMethod

Indicates whether this state directly possesses a method named methodName.

SYNTAX
this.hasOwnMethod( methodName )
PARAMETERS
  • methodName : string
RETURNS

Boolean.

SEE ALSO

State::hasOwnMethod

apply

Invokes a state method, passing an array of arguments.

SYNTAX
this.apply( methodName, args )
PARAMETERS
  • methodName : string
  • argsopt : Array
RETURNS

The value returned by the invocation of the named method, or undefined if no such method can be invoked.

DISCUSSION

If the state method named by methodName exists locally or can be inherited via protostate or superstate, that function is applied with the provided args in the appropriate context, and its result is returned.

By default the context will be the owner. If the method was defined using state.bind, the context will be either the precise State in which the method is defined, or if the method is inherited from a protostate, the corresponding epistate belonging to the inheriting owner.

If the named method does not exist and cannot be inherited, a noSuchMethod event is emitted and the call returns undefined.

SEE ALSO

State::apply

call

The variadic companion to apply, where a state method is invoked with individually provided arguments.

SYNTAX
this.call( methodName, args... )
PARAMETERS
  • methodName : string
  • args... : individual arguments
SEE ALSO

State::call

event

SYNTAX
this.event( eventType, id )
this.event( eventType )
PARAMETERS
  • eventType : string
  • idopt : ( string | number | function )
RETURNS

A registered event listener function, or the number of listeners registered, for a given eventType.

If an id as returned by addEvent is provided, the event listener associated with that id is returned. If no id is provided, the number of event listeners registered to eventType is returned.

SEE ALSO

State::event

addEvent

Binds an event listener fn to the specified eventType.

ALIASES

on, bind

SYNTAX
this.addEvent( eventType, fn )
this.addEvent( eventType, fn, context )
PARAMETERS
  • eventType : string
  • fn : function
  • context = this : object
RETURNS

A unique identifier for the listener.

SEE ALSO

State::addEvent

removeEvent

Unbinds the event listener with either the specified id that was supplied by addEvent, or a direct reference to that function.

ALIASES

off, unbind

SYNTAX
this.removeEvent( eventType, id )
PARAMETERS
  • eventType : string
  • id : ( string | number | function )
SEE ALSO

State::removeEvent

emit

Invokes all listeners bound to the given eventType.

ALIASES

trigger

SYNTAX
this.emit( eventType )
this.emit( eventType, via )
this.emit( eventType, args )
this.emit( eventType, args, via )
this.emit( eventType, args, context )
this.emit( eventType, args, context, via )
PARAMETERS
  • eventType : string
  • args = [] : Array
  • context = this : object
  • via = VIA_ALL : number

Arguments for the listeners can be passed as an array to the args parameter.

NOTES

Listeners are invoked in the context of this state, or as specified by context.

Listeners bound to superstates and protostates of this are also invoked, unless otherwise directed by zeroing the VIA_SUPER or VIA_PROTO bits of via.

SEE ALSO

State::emit

guard

Describes the guards in effect for this state.

SYNTAX
this.guard( guardType )
PARAMETERS
  • guardType : string
RETURNS

An object containing the guard predicates and/or expressions for the specified guardType held on this state.

DISCUSSION

A guard is a map of functions or values that will be evaluated as either a predicate or boolean expression, respectively, to provide a determination of whether the owner’s currency will be admitted into or released from the state to which the guard is applied.

Valid guardTypes include admit and release.

NOTES

Guards are inherited from protostates, but not from superstates.

SEE ALSO

State::guard

addGuard

Adds a guard to this state, or augments an existing guard with additional entries.

SYNTAX
this.addGuard( guardType, guard )
PARAMETERS
  • guardType : string
  • guard : object
SEE ALSO

State::addGuard

removeGuard

Removes a guard from this state, or removes specific entries from an existing guard.

SYNTAX
this.removeGuard( guardType, keys )
PARAMETERS
  • guardType : string
  • keysopt : ( Array | string )
SEE ALSO

State::removeGuard

transition

SYNTAX
this.transition( transitionName )
PARAMETERS
  • transitionName : string
RETURNS

The transition expression named by transitionName registered to this state.

transitions

SYNTAX
this.transitions()
RETURNS

An object containing all of the transition expressions registered to this state.

addTransition

Registers a transition expression to this state.

SYNTAX
this.addTransition( transitionName, transitionExpression )
PARAMETERS
  • transitionName : string
  • transitionExpression : ( TransitionExpression | object )

removeTransition

Removes a registered transition expression from this state.

SYNTAX
this.removeTransition( transitionName )
PARAMETERS
  • transitionName : string

Events

construct

SYNTAX
function ( expression ) {}
( expression ) ->
PARAMETERS
  • expression : ( StateExpression | object )
DESCRIPTION

Immediately after a State instance has been fully constructed, it emits a construct event.

Listeners receive the expression object from which the state was constructed.

Since construction is not complete until the state’s substates have themselves been constructed, the full construct event sequence of a state tree proceeds bottom-up.

EXAMPLE
var mover = {};
state( mover, {
    construct: function ( expression ) {
        console.log( "root state constructed" );
    },

    Moving: {
        construct: function ( expression ) {
            console.log( "State '" + this.name() + "' constructed" );
        },

        Walking: {
            construct: function ( expression ) {
                console.log(
                    "State '" + this.name() + "' constructed" );
            }
        }
    }
});
// log <<< State 'Walking' constructed
// log <<< State 'Moving' constructed
// log <<< root state constructed
mover = {}
state mover,
  construct: ( expression ) ->
    console.log "root state constructed"
  
  Moving:
    construct: ( expression ) ->
      console.log "State '#{ @name() }' constructed"
    
    Walking:
      construct: ( expression ) ->
        console.log "State '#{ @name() }' constructed"

# log <<< State 'Walking' constructed
# log <<< State 'Moving' constructed
# log <<< root state constructed
SEE ALSO

Existential events

destroy

SYNTAX
function () {}
->
DESCRIPTION

A state is properly deallocated with a call to the destroy method of either itself or a superstate. The destroy event is emitted immediately prior to the state and its contents being cleared.

Listeners of destroy are called with no arguments.

SEE ALSO

Existential events

depart

SYNTAX
function ( transition ) {}
( transition ) ->
PARAMETERS
  • transition : Transition
DESCRIPTION

At the beginning of a transition, exactly one depart event is always emitted by the state from which the transition originates.

Listeners receive a reference to the involved transition.

SEE ALSO

Transitional events

exit

SYNTAX
function ( transition ) {}
( transition ) ->
PARAMETERS
  • transition : Transition
DESCRIPTION

During the ascending phase of a transition, an exit event is emitted by the origin state and any of its superstates that will no longer be active as a result of the transition.

Listeners receive a reference to the involved transition.

SEE ALSO

Transitional events

enter

SYNTAX
function ( transition ) {}
( transition ) ->
PARAMETERS
  • transition : Transition
DESCRIPTION

During the descending phase of a transition, an enter event is emitted by each state that will become newly active, including the target state.

Listeners receive a reference to the involved transition.

SEE ALSO

Transitional events

arrive

SYNTAX
function ( transition ) {}
( transition ) ->
PARAMETERS
  • transition : Transition
DESCRIPTION

At the end of a transition, exactly one arrive event is always emitted by the transition’s target state.

Listeners receive a reference to the involved transition.

SEE ALSO

Transitional events

mutate

SYNTAX
function ( mutation, residue, before, after ) {}
( mutation, residue, before, after ) ->
PARAMETERS
  • mutation : object
  • residue : object
  • before : object
  • after : object
DESCRIPTION

When a state’s contents are altered, it emits a mutate event containing the changes made relative to its immediately prior condition.

Listeners receive the contents of the mutation experienced by the state, the residue containing the contents displaced by the mutation, and a full expression of the state’s contents both before and after the mutation.

SEE ALSO

mutate (method)

State::mutate

noSuchMethod

SYNTAX
function ( methodName, args ) {}
( methodName, args ) ->
PARAMETERS
  • methodName : string
  • args : Array
DESCRIPTION

When a method is called on an object for which no implementation exists given its current state, a noSuchMethod event is emitted.

Listeners receive the methodName of the method that was called, and an args array of the arguments that were passed to the call.

SEE ALSO

State::apply

noSuchMethod:name

SYNTAX
function ( arg0, arg1, ... ) {}
( args... ) ->
PARAMETERS
  • args... : var
DESCRIPTION

A generic noSuchMethod event is immediately followed by the emission of a specific noSuchMethod:name event, where name specifies the method that was called.

Listeners receive the arguments as they were passed to the call.

SEE ALSO

State::apply


Transition

A Transition is a transient State temporarily adopted as the owner object’s current state as it changes from one of its proper States to another.

A transition acts within the domain of the least common ancestor between its origin and target states. During this time it behaves as if it were a substate of that domain state, inheriting method calls and propagating events in the familiar fashion.

Transitions Transition

Properties

owner

this.owner

References the State to which this transition is currently attached during its traversal from origin through domain toward target.

root

this.root

References the State to which this transition is currently attached during its traversal from origin to target.

superstate

this.superstate

References the State to which this transition is currently attached during its traversal from origin through domain toward target.

origin

this.origin

References the owner’s most recently current State that is not itself a Transition — i.e., the state from which this transition originally emerged.

source

this.source

References the State or Transition that was current immediately prior to this transition.

target

this.target

References the intended destination State for this transition.

Methods

wasAborted

this.wasAborted()

Returns false if this transition has reached its target and completed successfully.

Returns true if this was aborted prior to reaching target.

Returns undefined if this has not yet been completed or aborted.

start

this.start( args... )

Automatically invoked as a result of a call to State.change.

end

this.end()

Used to signal the end of this transition’s action.

Upon reaching the top of its domain, a transition will invoke its action function, which is responsible for calling end() to signal that it is finished and ready for the transition to begin the descending phase of the traversal to target.

The transition lifecycle

Events

enter

function () {}
->

Immediately after currency is transferred to the transition from the source state, the transition emits an enter event.

Transitional events

start

function ( args... ) {}
( args... ) ->
  • args... : var

In the change call that instigated a transition, if the options argument included an args array, then these elements of options.args are passed as arguments to the transition’s start method, which relays them to listeners of the start event.

Transitional events

end

function ( args... ) {}
( args... ) ->
  • args... : var

A transition’s action phase is ended by calling its end method, and any arguments it receives are relayed to listeners of the transition’s end event.

If the transition bears no action, then arguments relayed to listeners of the transition’s start event are also relayed to listeners of the end event, which is emitted immediately after start.

Transitional events

exit

function () {}
->

Just before currency is transferred from a transition to its target state, an exit event is emitted by the transition.

Transitional events