Skip to content

Commit

Permalink
refined: node example code
Browse files Browse the repository at this point in the history
  • Loading branch information
valango committed Jul 12, 2015
1 parent 2197e7a commit a231edc
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 64 deletions.
1 change: 0 additions & 1 deletion examples/README.md
Expand Up @@ -9,4 +9,3 @@ application main files.
Shows how to use event system to loosely couple application modules and
achieve encapsulation. Each module knows only it's own domain plus *eventist*
API.

52 changes: 35 additions & 17 deletions examples/node/console.js
@@ -1,61 +1,79 @@
/**
* Console app does nothing clever. Most of code below is actually suicidal.
* console.js
*
* This app does nothing clever, but it illustrates some basic patterns
* of event-driven design.
*
* @author Villem Alango <villem.alango@gmail.com>
*/

'use strict';

// Event bus is the only connection between functional modules.
var bus = require('eventist')();
var emit = bus.emit;
var logging = true;

// Override the original method for logging purposes.
bus.emit = function () {
logging && emit.apply(bus, ['ui', 'log', Array.prototype.join.call(arguments, '::')]);
return emit.apply(bus, arguments);
};

/*
Application logic:
- maintaining dynamic configuration and connections between modules;
- implementing some functions of existential significance.
*/
bus
.on('module.connected', function () {
return true;
})
.once('module.quit', function (name) {
// Make a dramatic farewell before finishing the seppuku.
bus.send('ui', 'say',
['Ewwww... you have killed my', name, '!!! :,('].join(' '));
var left = 9
, die = function () {
, die = function () { // ... doing it loud and slowly.
if (left) {
bus.send('ui', 'say',
['I\'ll die in', left, 'seconds...'].join(' '));
left -= 3;
setTimeout(die, 3000);
} else {
bus.send('ui', 'say', 'Good-bye, Cruel World!');
bus.send('app', 'close', 'world!');
bus.send('app', 'close');
}
};
die();
})
// Some application-level events are handled here.
.on('app', function (cmd, a) {
if (cmd === 'close') {
bus.send('ui', 'say', 'Have a great day!');
process.exit(0);
} else if (cmd === 'load.filter') {
bus.send('ui', 'say', 'loading sfaety filter...');
require('./filter')(bus);
bus.send('ui', 'prompt');
}else if(cmd === 'log'){
logging = !!a;
} else {
return void 0;
switch (cmd) {
case 'close':
bus.send('ui', 'say', 'Have a great day!');
process.exit(0);
break; // Just to keep jshint happy.

case 'load.filter':
bus.send('ui', 'say', 'loading safety filter...');
require('./filter')(bus);
bus.send('ui', 'prompt');
break;

case 'log':
logging = !!a;
break;

default:
return void 0;
}
return true;
})
;
});

// Here we load functional modules

require('./ui-simple')(bus);
require('./decoder')(bus);
// Now we are good to go...
// And now we are good to go...
bus.send('ui', 'prompt');
62 changes: 43 additions & 19 deletions examples/node/decoder/index.js
Expand Up @@ -7,59 +7,83 @@
'use strict';

var bus;
var tolerance = 1;
var tolerance = 1; // Crossing 0 threshold will start suicide sequence.
var retry = false; // Flag preventing potential message translation deadlock.
var decode;

var logics = function (command, a) {
/**
* Make a last attempt to handle unknown user input and succumb to depression
* if that fails.
*
* @param {string} command
*/
var lastTry = function(command){

var res = !retry && bus.emit('app', 'bad-user', command);

if (res !== void 0) { // Take a chance with translated value.
res && (retry = true) && bus.send('user', res);
} else if (tolerance) {
bus.send('ui', 'say',
['I do not understand! Type "help", if you mind...',
tolerance, 'try left.'].join(' '));
--tolerance;
bus.send('ui', 'prompt');
} else { // Module suicide - letting the whole world to know.
bus.off('user', decode);
bus.send('module.quit', 'decoder');
bus = void 0;
}
};

/* jshint maxcomplexity:10 */
decode = function (command) {

switch (command) {
case 'help':
bus.send('ui', 'say',
'Available commands: clear, filter, help, log on, log off, hello, exit, quit');
break;

case 'clear':
bus.send('ui', 'clear');
break;

case 'filter':
bus.send('app', 'load.filter');
return true;
return true; // Avoid an extra prompt.

case 'hello':
bus.send('ui', 'say', 'world!');
break;

case 'log':
case 'log on':
bus.send('app', 'log', 1);
break;

case 'log off':
bus.send('app', 'log', 0);
break;

case 'exit':
case 'quit':
bus.send('app', 'close');
break;

default:
if (tolerance) {
bus.send('ui', 'say',
['I do not understand! Type "help" if you mind...', tolerance, 'try left.'].join(' '));
--tolerance;
bus.send('ui', 'prompt');
} else {
bus.off('user', logics);
bus.send('module.quit', 'decoder');
bus = void 0;
}
return;
return lastTry(command);
}
tolerance = 1;
retry = false; // Here after successful processing -
tolerance = 1; // reset the doom counter.
bus.send('ui', 'prompt');
return true;
};

var init = function (busInstance) {

bus = busInstance;

bus
.on('user', logics)
(bus = busInstance)
.on('user', decode)
.send('module.connected', 'decoder');
};

Expand Down
56 changes: 35 additions & 21 deletions examples/node/filter/index.js
Expand Up @@ -8,33 +8,47 @@

var bus, count = 0;

var logics = function (command) {

switch (command) {
case 'help':
case 'clear':
case 'filter':
case 'hello':
case 'log':
case 'log on':
case 'log off':
case 'exit':
case 'quit':
return void 0;
/*
Event app/bad-user/command is emitted by decoder on unknown command.
Replacement to this command can be sent as a return value.
*/
var translate = function (command) {

if (command === 'bad-user') {
if (--count <= 0) { // Provide help, but not too often.
count = 5;
return 'help';
}
bus.send('ui', 'prompt');
return null; // User input will be ignored.
}
if (--count <= 0) {
bus.send('user', 'help');
count = 5;
};

/*
Because being registered after original decoder, this handler receives
user input before the original one and can effectively filter/translate
everything.
*/
var decode = function (command) {
if (command === 'help') { // Eat 'help' command...
if (count !== 5) { // except when it was sent by ourselves.
bus.send('ui', 'prompt');
return true; // Just disable it
}
} else if (command === 'filter off') { // Process special command here.
bus.send('ui', 'say', 'disbling safety filter...')
.off('app', translate).off('user', decode)
.send('ui', 'set.prompt', 'OHAY').send('ui', 'prompt');
return true;
}
return true;
// Returning undefined value here allows the original decoder to be invoked.
};

var init = function (busInstance) {

bus = busInstance;

bus
.on('user', logics)
(bus = busInstance)
.on('app', translate)
.on('user', decode)
.send('module.connected', 'filter')
.send('ui', 'set.prompt', 'BABY');
};
Expand Down
10 changes: 4 additions & 6 deletions examples/node/ui-simple/index.js
@@ -1,6 +1,6 @@
/**
* Simple UI receives translates user input and performs rudimentary
* output functions.
* Simple UI receives translates user input into 'user' events
* and performs rudimentary output functions.
*
* @author Villem Alango <villem.alango@gmail.com>
*/
Expand Down Expand Up @@ -58,18 +58,16 @@ var logics = function (cmd, a1) {

var init = function (busInstance) {

bus = busInstance;

bus
(bus = busInstance)
.on('ui', logics)
.send('module.connected', name);

clear();
setPrompt('OHAI');

// Actual input feed event listener.
rl.on('line', function (line) {
var input = line.trim();

bus.send('user', input);
}).on('close', function () {
bus.off('ui', logics).emit('app', 'close');
Expand Down
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -12,6 +12,7 @@
"postinstall": "examples/initialize"
},
"keywords": [
"bus",
"event",
"emitter",
"extendable",
Expand Down

0 comments on commit a231edc

Please sign in to comment.