Skip to content

Commit

Permalink
Added the transitioned event, which fires after the _onEnter hand…
Browse files Browse the repository at this point in the history
…ler of a new state has completed execution.

Added support for additional custom arguments to be passed to the `transition` call, which then get passed as arguments to the `_onEnter` handler of the new state.
  • Loading branch information
ifandelse committed Jan 6, 2016
1 parent f61f36f commit bfeef5e
Show file tree
Hide file tree
Showing 15 changed files with 194 additions and 32 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# machina v1.1.2
# machina v2.0.0

## What is it?
Machina.js is a JavaScript framework for highly customizable finite state machines (FSMs). Many of the ideas for machina have been *loosely* inspired by the Erlang/OTP FSM behaviors.
Expand Down
2 changes: 1 addition & 1 deletion bower.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "machina",
"version": "1.1.2",
"version": "2.0.0",
"main": [
"lib/machina.js"
],
Expand Down
9 changes: 9 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
### v2.0.0

* Refactored to use CommonJS modules and changed the build process to use webpack to generate a UMD.
* Added the `transitioned` event, which fires after the `_onEnter` handler of a new state has completed execution.
* Added support for additional custom arguments to be passed to the `transition` call, which then get passed as arguments to the `_onEnter` handler of the new state.
* Fixed issue reported in #110, where behavioral FSMs were not correctly configuring the hierarchy (listening to correct child FSMs, reporting composite state correctly, etc.).
* Removed Plato Reports.
* Added Karma-based runner and related files.

### v1.1.2

* Internal improvements to the `Fsm` prototype, thanks to @igncp.
Expand Down
2 changes: 1 addition & 1 deletion component.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "machina.js",
"version": "1.1.2",
"version": "2.0.0",
"main": "lib/machina.js",
"scripts": [
"lib/machina.js"
Expand Down
18 changes: 15 additions & 3 deletions lib/machina.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion lib/machina.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion lib/machina.min.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "machina",
"description": "A library for creating powerful and flexible finite state machines. Loosely inspired by Erlang/OTP's gen_fsm behavior.",
"version": "2.0.0-1",
"version": "2.0.0",
"homepage": "http://machina-js.org/",
"repository": {
"type": "git",
Expand Down
82 changes: 77 additions & 5 deletions spec/BehavioralFsm.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ function runBehavioralFsmSpec( description, fsmFactory ) {
namespace: fsm.namespace
}
} );
events[ 4 ].should.eql( {
events[ 5 ].should.eql( {
eventName: "handled",
data: {
client: client,
Expand Down Expand Up @@ -152,7 +152,7 @@ function runBehavioralFsmSpec( description, fsmFactory ) {
namespace: fsm.namespace
}
} );
events[ 4 ].should.eql( {
events[ 5 ].should.eql( {
eventName: "handled",
data: {
client: client,
Expand Down Expand Up @@ -218,6 +218,16 @@ function runBehavioralFsmSpec( description, fsmFactory ) {
}
} );
events[ 3 ].should.eql( { eventName: "ready-OnEnterFiring", data: undefined } );
events[ 4 ].should.eql( {
eventName: "transitioned",
data: {
fromState: "uninitialized",
action: "uninitialized.start",
toState: "ready",
client: client,
namespace: fsm.namespace
}
} );
} );
it( "should emit an 'invalidstate' event when attempting to transition into a non-existent state", function() {
var fsm = fsmFactory.instanceWithOptions();
Expand Down Expand Up @@ -320,6 +330,16 @@ function runBehavioralFsmSpec( description, fsmFactory ) {
eventName: "ready-OnEnterFiring",
data: undefined
},
{
data: {
action: "uninitialized.start",
client: client,
fromState: "uninitialized",
namespace: "specialSauceNamespace",
toState: "ready"
},
eventName: "transitioned"
},
{
eventName: "handling",
data: {
Expand Down Expand Up @@ -457,6 +477,16 @@ function runBehavioralFsmSpec( description, fsmFactory ) {
eventName: "done-OnEnterFiring",
data: undefined
},
{
data: {
action: "",
client: client,
fromState: "uninitialized",
namespace: "specialSauceNamespace",
toState: "done"
},
eventName: "transitioned"
},
{
eventName: "handling",
data: {
Expand Down Expand Up @@ -554,6 +584,16 @@ function runBehavioralFsmSpec( description, fsmFactory ) {
eventName: "ready-OnEnterFiring",
data: undefined
},
{
data: {
action: "uninitialized.letsDoThis",
client: client,
fromState: "uninitialized",
namespace: "specialSauceNamespace",
toState: "ready"
},
eventName: "transitioned"
},
{
eventName: "handling",
data: {
Expand Down Expand Up @@ -749,6 +789,16 @@ function runBehavioralFsmSpec( description, fsmFactory ) {
eventName: "ready-OnEnterFiring",
data: undefined
},
{
eventName: "transitioned",
data: {
action: "uninitialized.start",
client: client,
fromState: "uninitialized",
namespace: "specialSauceNamespace",
toState: "ready"
}
},
{
eventName: "handled",
data: {
Expand Down Expand Up @@ -860,7 +910,7 @@ function runBehavioralFsmSpec( description, fsmFactory ) {
fsm.handle( client, "start" );
events.map( function( evnt ) {
return evnt.eventName;
} ).should.eql( [ "transition", "handling", "transition", "ready-OnEnterFiring", "handled" ] );
} ).should.eql( [ "transition", "handling", "transition", "ready-OnEnterFiring", "transitioned", "handled" ] );
} );
it( "should allow specific events to be subscribed to", function() {
var fsm = fsmFactory.instanceWithOptions();
Expand Down Expand Up @@ -1094,8 +1144,30 @@ function runBehavioralFsmSpec( description, fsmFactory ) {

fsmB.handle( clientB, "letsDoThis" );
fsmB.handle( clientB, "start" );
eventA.length.should.equal( 5 );
eventB.length.should.equal( 4 );
eventA.length.should.equal( 6 );
eventB.length.should.equal( 5 );
} );
} );
describe( "When passing arguments to transition", function() {
it( "should pass the arguments to the _onEnter handler", function() {
var custom;
var fsm = fsmFactory.instanceWithOptions( {
states: {
uninitialized: {
start: function( client ) {
this.transition( client, "ready", "Custom args!" );
}
},
ready: {
_onEnter: function( client, customArgs ) {
custom = customArgs;
}
}
}
} );
var client = { name: "Dijkstra" };
fsm.handle( client, "start" );
custom.should.equal( "Custom args!" );
} );
} );
if ( fsmFactory.extendingWithStaticProps ) {
Expand Down
67 changes: 62 additions & 5 deletions spec/MachinaFsm.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ function runMachinaFsmSpec( description, fsmFactory ) {
namespace: fsm.namespace
}
} );
events[ 3 ].should.eql( {
events[ 4 ].should.eql( {
eventName: "handled",
data: {
inputType: "start",
Expand Down Expand Up @@ -127,7 +127,7 @@ function runMachinaFsmSpec( description, fsmFactory ) {
namespace: fsm.namespace
}
} );
events[ 3 ].should.eql( {
events[ 4 ].should.eql( {
eventName: "handled",
data: { inputType: "start",
delegated: true,
Expand Down Expand Up @@ -238,6 +238,15 @@ function runMachinaFsmSpec( description, fsmFactory ) {
eventName: "ready-OnEnterFiring",
data: undefined
},
{
data: {
action: "uninitialized.start",
fromState: "uninitialized",
namespace: "specialSauceNamespace",
toState: "ready"
},
eventName: "transitioned"
},
{
eventName: "handling",
data: {
Expand Down Expand Up @@ -356,6 +365,15 @@ function runMachinaFsmSpec( description, fsmFactory ) {
eventName: "done-OnEnterFiring",
data: undefined
},
{
data: {
action: "",
fromState: "uninitialized",
namespace: "specialSauceNamespace",
toState: "done"
},
eventName: "transitioned"
},
{
eventName: "handling",
data: {
Expand Down Expand Up @@ -437,6 +455,15 @@ function runMachinaFsmSpec( description, fsmFactory ) {
eventName: "ready-OnEnterFiring",
data: undefined
},
{
data: {
action: "uninitialized.letsDoThis",
fromState: "uninitialized",
namespace: "specialSauceNamespace",
toState: "ready"
},
eventName: "transitioned"
},
{
eventName: "handling",
data: {
Expand Down Expand Up @@ -610,6 +637,15 @@ function runMachinaFsmSpec( description, fsmFactory ) {
eventName: "ready-OnEnterFiring",
data: undefined
},
{
data: {
action: "uninitialized.start",
fromState: "uninitialized",
namespace: "specialSauceNamespace",
toState: "ready"
},
eventName: "transitioned"
},
{
eventName: "handled",
data: {
Expand Down Expand Up @@ -700,7 +736,7 @@ function runMachinaFsmSpec( description, fsmFactory ) {
fsm.handle( "start" );
events.map( function( evnt ) {
return evnt.eventName;
} ).should.eql( [ "handling", "transition", "ready-OnEnterFiring", "handled" ] );
} ).should.eql( [ "handling", "transition", "ready-OnEnterFiring", "transitioned", "handled" ] );
} );
it( "should allow specific events to be subscribed to", function() {
var fsm = fsmFactory.instanceWithOptions();
Expand Down Expand Up @@ -818,15 +854,36 @@ function runMachinaFsmSpec( description, fsmFactory ) {

// Acting on fsmA should not affect fsmB
fsmA.handle( "start" );
eventA.length.should.equal( 4 );
eventA.length.should.equal( 5 );
eventB.length.should.equal( 0 );

fsmB.handle( "letsDoThis" );
fsmB.handle( "start" );
eventA.length.should.equal( 4 );
eventA.length.should.equal( 5 );
eventB.length.should.equal( 2 );
} );
} );
describe( "When passing arguments to transition", function() {
it( "should pass the arguments to the _onEnter handler", function() {
var custom;
var fsm = fsmFactory.instanceWithOptions( {
states: {
uninitialized: {
start: function() {
this.transition( "ready", "Custom args!" );
}
},
ready: {
_onEnter: function( customArgs ) {
custom = customArgs;
}
}
}
} );
fsm.handle( "start" );
custom.should.equal( "Custom args!" );
} );
} );
if ( fsmFactory.extendingWithStaticProps ) {
describe( "When adding static props", function() {
it( "should inherit static (constructor-level) members", function() {
Expand Down
12 changes: 6 additions & 6 deletions spec/hierarchical.BehavioralFsm.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ describe( "Hierarchical machina.BehavioralFsm", function() {
client.__machina__[ "vehicle-signal" ].state.should.equal( "green" );
} );
it( "should issue reset input to child FSM of active parent state", function() {
events[ 5 ].should.eql( {
events[ 6 ].should.eql( {
name: "handling",
data: {
inputType: "_reset",
Expand All @@ -43,7 +43,7 @@ describe( "Hierarchical machina.BehavioralFsm", function() {
} );
} );
it( "should emit a 'vehicles - green' event", function() {
events[ 8 ].should.eql( { name: "vehicles", data: { status: "green", client: client } } );
events[ 9 ].should.eql( { name: "vehicles", data: { status: "green", client: client } } );
} );
it( "should not be listening to any events from child FSM of inactive parent state", function() {
_.any( events, function( item ) {
Expand Down Expand Up @@ -197,7 +197,7 @@ describe( "Hierarchical machina.BehavioralFsm", function() {
events[ 2 ].should.eql( { name: "vehicles", data: { status: "red", client: client } } );
} );
it( "should have child FSM of active parent state handle _reset input", function() {
events[ 4 ].should.eql( {
events[ 5 ].should.eql( {
name: "handling",
data: {
inputType: "_reset",
Expand All @@ -209,7 +209,7 @@ describe( "Hierarchical machina.BehavioralFsm", function() {
} );
} );
it( "should emit a 'pedestrians - walk' event", function() {
events[ 7 ].should.eql( { name: "pedestrians", data: { status: "Walk", client: client } } );
events[ 8 ].should.eql( { name: "pedestrians", data: { status: "Walk", client: client } } );
} );
} );
describe( "and parent FSM transitions into previously held state", function() {
Expand All @@ -234,7 +234,7 @@ describe( "Hierarchical machina.BehavioralFsm", function() {
this.clock.restore();
} );
it( "should cause child FSM to handle a _reset input", function() {
events[ 18 ].should.eql( {
events[ 22 ].should.eql( {
name: "transition",
data: {
fromState: "yellow",
Expand All @@ -246,7 +246,7 @@ describe( "Hierarchical machina.BehavioralFsm", function() {
} );
} );
it( "should emit a 'vehicles - green' event", function() {
events[ 19 ].should.eql( { name: "vehicles", data: { status: "green", client: client } } );
events[ 23 ].should.eql( { name: "vehicles", data: { status: "green", client: client } } );
} );
} );
} );
Expand Down
Loading

0 comments on commit bfeef5e

Please sign in to comment.