Skip to content

Commit

Permalink
added callback support
Browse files Browse the repository at this point in the history
  • Loading branch information
kernow committed Apr 15, 2009
1 parent aca6554 commit f46cd3a
Show file tree
Hide file tree
Showing 10 changed files with 237 additions and 9 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "test/js/jsmocha"]
path = test/js/jsmocha
url = git://github.com/kernow/jsmocha.git
20 changes: 20 additions & 0 deletions lib/state_machine/callback.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@

SM.Callback = function(options, machine, block) {
this.options = options;
this.machine = machine;
this.block = block;
return this;
}

SM.Callback.prototype = {
run: function() {
console.log("running a callback");
},
match: function(state) {
return this.options.to == state ? true : false;
},
run: function() {
if(this.block){ this.block() };
if(this.options.do){ this.machine.object[this.options.do]() };
}
}
32 changes: 32 additions & 0 deletions lib/state_machine/callback_collection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@

SM.CallbackCollection = function() {
this.callbacks = [];
this.callbacks['before'] = [];
this.callbacks['after'] = [];
return this;
}

SM.CallbackCollection.prototype = {
add: function(type, options, machine, block) {
var callback = new SM.Callback(options, machine, block);
this.callbacks[type].push(callback);
},
all: function() {
return this.callbacks;
},
before: function() {
return this.callbacks['before'];
},
after: function() {
return this.callbacks['after'];
},
run: function(type, state) {
var callbacks = this.callbacks[type];
for(var i=0;i<callbacks.length;i++){
if(callbacks[i].match(state)){
callbacks[i].run();
}
}
}

}
2 changes: 1 addition & 1 deletion lib/state_machine/event_collection.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ SM.EventCollection = function(){

SM.EventCollection.prototype = {
add: function(name, machine, options) {
var event = new SM.Event(name, machine, options)
var event = new SM.Event(name, machine, options);
this.events.push(event);
return event;
},
Expand Down
12 changes: 8 additions & 4 deletions lib/state_machine/machine.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@

SM.Machine = function(name, object, options, block) {
this.events = new SM.EventCollection();
this.states = new SM.StateCollection();
this.events = new SM.EventCollection();
this.states = new SM.StateCollection();
this.callbacks = new SM.CallbackCollection();

this.object = object;
this.machine_name = name;
Expand All @@ -20,8 +21,11 @@ SM.Machine.prototype = {
object[name+'_events'] = this.events.all();
object[name+'_states'] = this.states.all();
},
before_transition: function(){
// TODO
before_transition: function(options, block){
var callback = this.callbacks.add('before', options, this, block);
},
after_transition: function(options, block){
var callback = this.callbacks.add('after', options, this, block);
},
event: function(name, options, block) {
var event = this.events.add(name, this, options);
Expand Down
9 changes: 8 additions & 1 deletion lib/state_machine/transition.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,14 @@ SM.Transition = function(machine, event, from, to){

SM.Transition.prototype = {
perform: function() {
// TODO: callbacks
this.before();
this.machine.set_state(this.to);
this.after();
},
before: function() {
this.machine.callbacks.run('before', this.to);
},
after: function() {
this.machine.callbacks.run('after', this.to);
}
}
17 changes: 14 additions & 3 deletions test/acceptance.html
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>js_state_machine - Acceptance tests</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>js_state_machine - Acceptance tests</title>

<link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.5.2/build/logger/assets/skins/sam/logger.css" />
<link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.5.2/build/fonts/fonts-min.css" />
Expand All @@ -11,23 +11,34 @@
<!-- YUI -->
<script src="js/yui/build/yui/yui-min.js" type="text/javascript"></script>

<!-- jsMocha -->
<!-- jsMocha -->
<script type="text/javascript" src="js/jsmocha/lib/jsmocha.js"></script>
<script type="text/javascript" src="js/jsmocha/lib/jsmocha/expectation_list.js"></script>
<script type="text/javascript" src="js/jsmocha/lib/jsmocha/expectation.js"></script>
<script type="text/javascript" src="js/jsmocha/lib/jsmocha/parameters_matcher.js"></script>
<script type="text/javascript" src="js/jsmocha/lib/jsmocha/mock.js"></script>
<script type="text/javascript" src="js/jsmocha/lib/adapters/yui-adapter.js"></script>

<!-- js_state_machine -->
<script type="text/javascript" src="../lib/state_machine.js"></script>
<script type="text/javascript" src="../lib/state_machine/machine.js"></script>
<script type="text/javascript" src="../lib/state_machine/state.js"></script>
<script type="text/javascript" src="../lib/state_machine/event.js"></script>
<script type="text/javascript" src="../lib/state_machine/guard.js"></script>
<script type="text/javascript" src="../lib/state_machine/transition.js"></script>
<script type="text/javascript" src="../lib/state_machine/callback.js"></script>
<script type="text/javascript" src="../lib/state_machine/state_collection.js"></script>
<script type="text/javascript" src="../lib/state_machine/event_collection.js"></script>
<script type="text/javascript" src="../lib/state_machine/guard_collection.js"></script>
<script type="text/javascript" src="../lib/state_machine/callback_collection.js"></script>


<!-- Test suit -->
<script type="text/javascript" src="js/test_runner.js"></script>
<script type="text/javascript" src="js/state_machine_tests.js"></script>
<script type="text/javascript" src="js/transition_tests.js"></script>
<script type="text/javascript" src="js/event_tests.js"></script>
<script type="text/javascript" src="js/callback_tests.js"></script>

</head>

Expand Down
149 changes: 149 additions & 0 deletions test/js/callback_tests.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@

jsStateMachineTests.CallbackTests = function(Y) {
var testSuite = new Y.Test.Suite("Callback");

testSuite.add(new Y.Test.Case({

name: "general",

setUp : function () {
this.car = {};
},

tearDown : function () {
delete this.car;
},

testCanRegisterBeforeTransition : function () {
new Mock(this.car);
this.car.expects('turn_on_radio');

new SM.StateMachine('state', this.car, { initial: 'parked' }, function(machine){

machine.before_transition({to: 'idling', do: 'turn_on_radio'});

machine.event('start', {}, function(event){
event.transition({ from: 'parked', to: 'idling' });
});
});
this.car.start();
Y.Assert.isTrue(this.car.jsmocha.verify(), this.car.jsmocha.report());
},
testCanRegisterAfterTransition : function () {
new Mock(this.car);
this.car.expects('open_sunroof');

new SM.StateMachine('state', this.car, { initial: 'parked' }, function(machine){

machine.after_transition({to: 'idling', do: 'open_sunroof'});

machine.event('start', {}, function(event){
event.transition({ from: 'parked', to: 'idling' });
});
});
this.car.start();
Y.Assert.isTrue(this.car.jsmocha.verify(), this.car.jsmocha.report());
},
testCanRegisterBeforeAndAfterTransition : function () {
new Mock(this.car);
this.car.expects('turn_on_radio');
this.car.expects('open_sunroof');

new SM.StateMachine('state', this.car, { initial: 'parked' }, function(machine){

machine.before_transition({to: 'idling', do: 'turn_on_radio'});
machine.after_transition({to: 'idling', do: 'open_sunroof'});

machine.event('start', {}, function(event){
event.transition({ from: 'parked', to: 'idling' });
});
});
this.car.start();
Y.Assert.isTrue(this.car.jsmocha.verify(), this.car.jsmocha.report());
},
testOnlyMatchedCallbacksAreRun : function () {
new Mock(this.car);
this.car.expects('turn_on_radio');
this.car.expects('turn_off_radio').never();
this.car.expects('open_sunroof');
this.car.expects('close_sunroof').never();

new SM.StateMachine('state', this.car, { initial: 'parked' }, function(machine){

machine.before_transition({to: 'idling', do: 'turn_on_radio'});
machine.before_transition({to: 'parked', do: 'turn_off_radio'});

machine.after_transition({to: 'idling', do: 'open_sunroof'});
machine.after_transition({to: 'parked', do: 'close_sunroof'});

machine.event('start', {}, function(event){
event.transition({ from: 'parked', to: 'idling' });
});
machine.event('stop', {}, function(event){
event.transition({ from: 'idling', to: 'parked' });
});
});
this.car.start();
Y.Assert.isTrue(this.car.jsmocha.verify(), this.car.jsmocha.report());
},
testMultipleCallbacksAreRun : function () {
new Mock(this.car);
this.car.expects('turn_on_radio');
this.car.expects('turn_off_radio');
this.car.expects('open_sunroof');
this.car.expects('close_sunroof');

new SM.StateMachine('state', this.car, { initial: 'parked' }, function(machine){

machine.before_transition({to: 'idling', do: 'turn_on_radio'});
machine.before_transition({to: 'parked', do: 'turn_off_radio'});

machine.after_transition({to: 'idling', do: 'open_sunroof'});
machine.after_transition({to: 'parked', do: 'close_sunroof'});

machine.event('start', {}, function(event){
event.transition({ from: 'parked', to: 'idling' });
});
machine.event('stop', {}, function(event){
event.transition({ from: 'idling', to: 'parked' });
});
});
this.car.start();
this.car.stop();
Y.Assert.isTrue(this.car.jsmocha.verify(), this.car.jsmocha.report());
},
testCanRegisterCallbackBlock : function () {
callback_checker = new Mock();
callback_checker.expects('turn_on_radio');
callback_checker.expects('turn_off_radio');

new Mock(this.car);
this.car.expects('close_sunroof');

new SM.StateMachine('state', this.car, { initial: 'parked' }, function(machine){

machine.before_transition({to: 'idling'}, function(){
callback_checker.turn_on_radio();
});
machine.before_transition({to: 'parked', do: 'close_sunroof'}, function(){
callback_checker.turn_off_radio();
});

machine.event('start', {}, function(event){
event.transition({ from: 'parked', to: 'idling' });
});

machine.event('stop', {}, function(event){
event.transition({ from: 'idling', to: 'parked' });
});
});
this.car.start();
this.car.stop();
Y.Assert.isTrue(callback_checker.jsmocha.verify(), callback_checker.jsmocha.report());
Y.Assert.isTrue(this.car.jsmocha.verify(), this.car.jsmocha.report());
delete callback_checker;
},
}));

return testSuite;
};
1 change: 1 addition & 0 deletions test/js/jsmocha
Submodule jsmocha added at 19174a
1 change: 1 addition & 0 deletions test/js/test_runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ YUI({base: 'js/yui/build/'}).use("console", "yuitest", function(Y) {
Y.Test.Runner.add(jsStateMachineTests.StateMachineTests(Y));
Y.Test.Runner.add(jsStateMachineTests.TransitionTests(Y));
Y.Test.Runner.add(jsStateMachineTests.EventTests(Y));
Y.Test.Runner.add(jsStateMachineTests.CallbackTests(Y))
Y.Test.Runner.run();
});

0 comments on commit f46cd3a

Please sign in to comment.