Skip to content

Instantly share code, notes, and snippets.

@summer4096
Created October 17, 2012 06:10
Show Gist options
  • Save summer4096/3903942 to your computer and use it in GitHub Desktop.
Save summer4096/3903942 to your computer and use it in GitHub Desktop.
Runner for streaming templates
var events = require('events');
var stream = require('stream');
var util = require('util');
var runner = function(template, output) {
stream.call(this);
this.readable = true;
this.writable = true;
this.inStatement = false;
this.waiting = {};
this.i = 0;
this.template = template;
this.variables = {};
this.varEvents = new events.EventEmitter();
this.running = false;
if (output) {
this.pipe(output);
}
};
util.inherits(runner, stream);
runner.prototype.pipe = function(output){
stream.prototype.pipe.apply(this, arguments);
if (!this.running) {
this.running = true;
this.next();
}
};
runner.prototype.write = function(data){
this.emit('data', data);
};
runner.prototype.next = function(){
var line = this.template[ this.i ];
if (typeof line == 'undefined') return;
this.i++;
if (typeof line == 'string') {
this.emit('data', line);
this.next();
} else {
var functionName = line.slice(0, 1);
var args = line.slice(1);
this.fn[ functionName ].apply(this, args);
}
};
runner.prototype.set = function(varName, value){
this.variables[ varName ] = value;
this.varEvents.emit(varName, value);
};
runner.prototype.get = function(varName, callback){
if (typeof this.variables[ varName ] != 'undefined') {
callback(this.variables[ varName ]);
} else {
this.varEvents.once(varName, function(value){
callback(value);
});
}
};
runner.prototype.fn = {};
runner.prototype.filters = {};
runner.prototype.fn.var = function(varName){
var args = Array.prototype.slice.call(arguments);
var self = this;
var filterList = args.slice(1);
var firstFilter;
var lastFilter;
for (var i in filterList) {
var filterName = filterList[i][0];
var filterArgs = filterList[i].slice(1);
var thisFilter = new this.filters[ filterName ](filterArgs);
if (!firstFilter) {
firstFilter = thisFilter;
}
if (lastFilter) {
lastFilter.pipe(thisFilter);
}
lastFilter = thisFilter;
}
if (lastFilter) {
var self = this;
lastFilter.on('data', function(data){
self.emit('data', data);
});
lastFilter.on('end', function(){
self.next();
});
}
this.get(varName, function(value){
if (filterList.length) {
if (typeof value == 'string') {
firstFilter.write(value);
firstFilter.end();
} else {
value.pipe(firstFilter);
}
} else {
if (typeof value == 'string') {
self.write(value);
self.next();
} else {
value.pipe(self);
}
}
});
};
var makeFilter = function(){
var newFilter = function(args){
stream.call(this);
this.readable = true;
this.writable = true;
this.args = args;
this.once('newListener:data', function(){
this.start();
});
this.on('end', function(){
this.finish();
});
};
util.inherits(newFilter, stream);
newFilter.prototype.end = function(){
this.emit('end');
};
newFilter.prototype.addListener = newFilter.prototype.on = function(event, listener){
events.EventEmitter.prototype.addListener.apply(this, arguments);
this.emit('newListener:'+event, listener);
}
newFilter.prototype.once = function(event, listener){
events.EventEmitter.prototype.once.apply(this, arguments);
this.emit('newListener:'+event, listener);
}
newFilter.prototype.write = function(data){
this.emit('data', data);
};
newFilter.prototype.start = function(){};
newFilter.prototype.finish = function(){};
return newFilter;
};
var uppercase = makeFilter();
uppercase.prototype.write = function(data){
this.emit('data', data.toUpperCase());
};
runner.prototype.filters.uppercase = uppercase;
var wrap = makeFilter();
wrap.prototype.start = function(){
this.emit('data', this.args[0]);
};
wrap.prototype.finish = function(){
this.emit('data', this.args[1]);
};
runner.prototype.filters.wrap = wrap;
var compiled = [
'<!DOCTYPE html>\n<html lang="en">\n\t<head>\n\t\t<title>',
['var', 'title', ['uppercase'], ['wrap', '[[ ', ' ]]']],
'</title>\n\t</head>\n\t<body>\n\t\t<h1>',
['var', 'title'],
'</h1>\n\t</body>\n</html>\n'
];
var testy = new runner(compiled, process.stdout);
setTimeout(function(){
testy.set('title', 'Test page');
}, 1000);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment