Monday, July 5, 2010

Prettying Up Vow.js and Fab.js with Macros

‹prev | My Chain | next›

Up first tonight, I combine my vows.js batches:
var suite = vows.describe('just_playing').
addBatch({
'with a query string': {
// topic + vows
}
}).
addBatch({
'POSTing data': {
// topic + vows
}
}).export(module);
I had overlooked that batches were only meant for code that needs to run sequentially. My fab.js apps can be accessed at any point, so I might as well consolidate:
var suite = vows.describe('just_playing').
addBatch({
'with a query string': {
// topic + vows
},
'POSTing data': {
// topic + vows
}
}).export(module);
Up next, I think I can DRY up my two topics:
var suite = vows.describe('just_playing').
addBatch({
'with a query string': {
topic: function() {
var topic = this;
var upstream_listener = player_from_querystring.call(
function(obj) { topic.callback(null, obj.body); }
);
upstream_listener({
url: { search : "?player=foo&x=1&y=2" },
headers: { cookie: null }
});

},

// vows
},
'POSTing data': {
topic: function() {
var topic = this;
var upstream_listener = player_from_querystring.call(
function(obj) { topic.callback(null, obj); }
);
upstream_listener({body: "foo"});

},

// vows
}
}).export(module);
The vows.js documentation suggests that GET calls in the topic can be factored out into an api.get call. In my two topics, I am sending data to the upstream via the listener that it returns. I try this:
var api = {
fab: {
send_obj: function(obj) {
return function () {
var topic = this;
var upstream_listener = player_from_querystring.call(
function(obj) { topic.callback(null, obj.body); }
);
upstream_listener(obj);
};
}
}
};
With that, I can rewrite my test suite as:
var suite = vows.describe('just_playing').
addBatch({
'with a query string': {
topic: api.fab.send_obj({
url: { search : "?player=foo&x=1&y=2" },
headers: { cookie: null }
}),

// cows
},
'POSTing data': {
topic: api.fab.send_obj({body: "foo"}),

// vows
}
}).export(module);
Ahhh. That is nice. Unfortunately, when I run the suite, I get:
cstrom@whitefall:~/repos/my_fab_game$ vows --spec

♢ just_playing

/home/cstrom/repos/my_fab_game/test/just_playing.js:14
function(obj) { topic.callback(null, obj.body); }
^
TypeError: Cannot read property 'body' of undefined
at /home/cstrom/repos/my_fab_game/test/just_playing.js:14:51
at lib/player_from_querystring.js:25:7
at Object.<anonymous> (/home/cstrom/repos/my_fab_game/test/just_playing.js:16:9)
at run (/home/cstrom/.node_libraries/.npm/vows/0.4.5/package/lib/vows/suite.js:125:31)
at EventEmitter.<anonymous> (/home/cstrom/.node_libraries/.npm/vows/0.4.5/package/lib/vows/suite.js:195:40)
at EventEmitter.emit (events:42:20)
at /home/cstrom/.node_libraries/.npm/vows/0.4.5/package/lib/vows/suite.js:147:58
at EventEmitter._tickCallback (node.js:48:25)
at node.js:204:9
Aw nuts. Thankfully, that is easily fixed. When I send in non-querystrings, I expect an undefined response. If the response is undefined, then there certainly will not be a body attribute associated with the response, so I rewrite my macro as:
var api = {
fab: {
send_obj: function(obj) {
return function () {
var topic = this;
var upstream_listener = player_from_querystring.call(
function(obj) { topic.callback(null, obj && obj.body); }
);
upstream_listener(obj);
};
}
}
};
With that, my suite passes in addition to being nicely compact:
cstrom@whitefall:~/repos/my_fab_game$ vows --spec

♢ just_playing

with a query string
✓ is player
✓ has unique ID
✓ has X coordinate
✓ has Y coordinate
POSTing data
✓ is null response

✓ OK » 5 honored (0.090s)
I think that is as good as I can get it. Unless I can come up with further improvements, I will move onto plying my hard-earned vows.js know-how on binary (fab) apps tomorrow.


Day #155

No comments:

Post a Comment