Permalink
Browse files

Implement the first version of the helper lib.

Also include a sample implementation of the spec.
  • Loading branch information...
1 parent e6e08df commit 623563b67e9023e6518a5251409d042033e43d8c @creationix committed Jul 13, 2010
Showing with 51 additions and 32 deletions.
  1. +2 −0 README.markdown
  2. +37 −0 examples/corn.js
  3. 0 base.js → lib/grain.js
  4. +0 −25 simpleCompiler.js
  5. +0 −7 test.js
  6. +12 −0 testCorn.js
View
@@ -10,6 +10,8 @@ All template languages have 5 parts in common.
Ok, maybe the last one isn't that common, but in a NodeJS world where nothing blocks it's required for many use cases. Partial templates require usually that another external resource get loaded and compiled. If this resource is loaded over some IO then it's an asynchronous operation. Also it would be nice to be able to stream content to the browser as information is known.
+Grain is both a spec for interfaces between template languages and a helper library to help write compilers that follow the spec. Included is a sample template language called `Corn` that implements the spec using `grain`.
+
## Inversion of control
One way to handle the async nature of retrieving data is to pre-calculate all the data that's needed for a template to render, and then as the last step pass it to the template function which returns the output text in a single sync function call. This works and is very simple from the point of view of the author of the template language, but it's a lot of burden on the person using the template language.
View
@@ -0,0 +1,37 @@
+var grain = require('../lib/grain');
+var Buffer = require('buffer').Buffer;
+
+module.exports = function compile(template, locals, callback) {
+ var regex = /@([a-z$_][a-z0-9$_]*)\(([^\)]*)\)/g,
+ pos = 0, parts = [], match;
+
+ function addPlain(input) {
+ parts.push('chunks[' + parts.length + '] = ' + JSON.stringify(input).replace(/@[a-z$_][a-z0-9$_]*/g, function (match) {
+ return '" + ' + match.substr(1) + ' + "';
+ }).replace('"" + ', '').replace(' + ""', '') + ";"
+ );
+ }
+ while (match = regex.exec(template)) {
+ // Push sync content on the stack
+ if (match.index > pos) {
+ addPlain(template.substr(pos, match.index));
+ pos = match.index;
+ }
+ // Push on a async placeholder for the function call
+ parts.push('execute(' + parts.length + ', ' + match[1] + (match[2] ? ', [' + match[2] + ']' : '') + ');');
+ pos += match[0].length;
+ }
+ // If there is more sync content, push it on.
+ if (pos < template.length) {
+ addPlain(template.substr(pos));
+ }
+ // Add on header and footer to the generated code.
+ parts.unshift('chunks = new Array(' + parts.length + ');');
+ parts.push('check();');
+
+ // Generate the code using the grain helper
+ eval(grain(parts));
+
+ // Do a little currying for the user
+ return locals ? compile(locals, callback) : compile;
+};
View
File renamed without changes.
View
@@ -1,25 +0,0 @@
-var base = require('./base');
-var Buffer = require('buffer').Buffer;
-var sys = require('sys');
-
-module.exports = function compile(template, locals, callback) {
-
- var code = JSON.stringify(template).replace(/@[a-z$_][a-z0-9$_]*/g, function (match) {
- return '" + ' + match.substr(1) + ' + "';
- });
- eval(base(["chunks = new Array(1)", "chunks[0] = " + code, 'check()']));
-
- // // Generate the code
- // eval(base([
- // 'chunks = new Array(5);',
- // 'chunks[0] = "Hello " + planet + ", my name is ";',
- // 'execute(1, name);',
- // 'chunks[2] = " and I am ";',
- // 'execute(3, age);',
- // 'chunks[4] = " years old";',
- // 'check();'
- // ]));
-
- // Do a little currying for the user
- return locals ? compile(locals, callback): compile;
-}
View
@@ -1,7 +0,0 @@
-var compiler = require('./simpleCompiler');
-
-var fn = compiler("Hello @world, today is @today");
-console.log(fn +"");
-fn({world:"Earth",today:new Date()}, function (err, text) {
- console.log(text);
-});
View
@@ -0,0 +1,12 @@
+var Corn = require('./examples/corn');
+
+var fn = Corn("Hello @world, today is @today().");
+console.log(fn +"");
+fn({world:"Earth",today:function (callback) {
+ setTimeout(function () {
+ callback(null, new Date());
+ }, 100);
+ }}, function (err, text) {
+ if (err) throw err;
+ console.log(text);
+});

0 comments on commit 623563b

Please sign in to comment.