Permalink
Browse files

Simplified partial rendering, setup, version 0.2, lots of API changes…

…. Sorry
  • Loading branch information...
1 parent 76a3042 commit 6cfc22b707e0fa267add32a4e6f5f6f6cd0001be @chbrown committed May 5, 2012
Showing with 383 additions and 545 deletions.
  1. +1 −1 .gitignore
  2. +1 −1 LICENSE
  3. +12 −0 README.md
  4. +0 −33 demo.js
  5. +0 −1 index.js
  6. +0 −40 lib/amulet.js
  7. +0 −40 lib/cli.js
  8. +30 −0 lib/main.js
  9. +16 −15 lib/parsing.js
  10. +36 −0 lib/proto.js
  11. +58 −140 lib/rendering.js
  12. +22 −4 package.json
  13. +28 −28 tests/bench.js
  14. +0 −1 tests/extended_spec.json
  15. +46 −46 tests/lib.js
  16. +0 −1 tests/local_spec.json
  17. +1 −0 tests/mustache
  18. +90 −100 tests/run_mu_spec.js
  19. +0 −44 tests/run_single_example.js
  20. +0 −1 tests/spec
  21. +42 −49 tests/spec_test.js
View
@@ -1,4 +1,4 @@
.DS_Store
test/spec/
+node_modules/
notes.txt
-
View
@@ -1,5 +1,5 @@
Copyright (c) 2010 Ray Christopher Morgan (raycmorgan.com)
-Copyright (c) 2011 Christopher Brown (henrian.com)
+Copyright (c) 2011-2012 Christopher Brown (henrian.com)
MIT License:
View
@@ -19,3 +19,15 @@ Also, work on [Mu](https://github.com/raycmorgan/Mu) died off in the middle of 2
# License
MIT Licensed, 2010-2011
+
+
+var mu = require('./mu');
+
+var input = '';
+
+process.stdin.resume();
+process.stdin.setEncoding('utf8');
+process.stdin.on('data', function(chunk) {
+ input += chunk;
+});
+process.stdin.once('end', function() {
View
33 demo.js
@@ -1,33 +0,0 @@
-var sys = require('sys');
-var Mu = require('./lib/mu');
-
-Mu.templateRoot = './examples';
-
-var ctx = {
- name: "Chris",
- value: 10000,
- taxed_value: function() {
- return this.value - (this.value * 0.4);
- },
- in_ca: true
-};
-
-sys.puts("Outputting examples/simple.html.mu with a chunkSize of 10\n");
-
-Mu.render('simple.html', ctx, {chunkSize: 10}, function (err, output) {
- if (err) {
- throw err;
- }
-
- var buffer = '';
-
- output
- .addListener('data', function (c) {
- sys.print(c); // output chunk
- output.pause(); // pause for demo
- setTimeout(function () { // wait 500ms and resume for demo
- output.resume();
- }, 500);
- })
- .once('end', function () { sys.puts("\n\nDONE"); });
-});
View
@@ -1 +0,0 @@
-module.exports = require(__dirname + '/lib/mu');
View
@@ -1,40 +0,0 @@
-var rendering = require('./rendering');
-exports.root = rendering.root; // backwards compat!
-exports.settings = rendering.set; // backwards compat!
-exports.set = rendering.set; // a function
-exports.parseTemplate = rendering.parseTemplate;
-
-// todo:
-// implement ability to add names asap-ly, so that the first one can start rendering without its yield being specified yet
-
-// names can be either a string or an array of strings
-exports.render = function(names, context, output, callback) {
- // callback signature: function(err)
- var renderer = new rendering.StreamRenderer(false); // asap=false
- renderer.context = context;
- if (callback) {
- renderer.callback = callback;
- }
- if (output) {
- renderer.stream.pipe(output);
- }
- renderer.start(names);
- return renderer;
-};
-
-exports.init = function(output) {
- var renderer = new rendering.StreamRenderer(true); // asap=true
- if (output) {
- renderer.stream.pipe(output);
- }
- return renderer;
-};
-
-exports.renderString = function(names, context, callback) {
- // callback signature: function(err, string)
- // can I force it to be sync? callback is okay too, if not
- var renderer = new rendering.StringRenderer(callback);
- renderer.context = context;
- renderer.start(names);
- return renderer;
-};
View
@@ -1,40 +0,0 @@
-#!/usr/bin/env node
-
-var util = require('util');
-var mu = require('./mu');
-
-var input = '';
-
-process.stdin.resume();
-process.stdin.setEncoding('utf8');
-process.stdin.on('data', function(chunk) {
- input += chunk;
-});
-process.stdin.once('end', function() {
-
- // template = template.toString('utf8');
- // var parsed = parser.parse(template);
- //
- // if (~process.argv.indexOf('--tokens')) {
- // console.log(util.inspect(parsed, false, 20));
- // return;
- // }
- //
- // process.argv.forEach(function (arg) {
- // if (arg.indexOf('--view=') === 0) {
- // try {
- // var view = eval('(' + arg.replace('--view=', '') + ')');
- // } catch (e) {
- // console.log('\nData: ' + arg.replace('--view=', ''));
- // throw e;
- // }
- //
- // mu.renderText(template, view).on('data', util.print);
- // // .on('data', function (d) {
- // // util.print(d);
- // // });
- // }
- // });
-
-});
-
View
@@ -0,0 +1,30 @@
+var parsing = require('./parsing'),
+ rendering = require('./rendering');
+
+exports.set = parsing.set; // a function
+exports.parseTemplate = parsing.parseTemplate;
+
+// todo:
+// implement ability to add names asap-ly, so that the first one can start rendering without its yield being specified yet
+
+exports.render = function(output, names, context, callback) {
+ // @output: a string
+ // @names: an array of strings (coerces naked string to 1-array)
+ // @context: a string or an array of strings
+ // @callback: function(err) { }
+ var asap = names && context && callback;
+ if (callback === undefined) callback = function() {};
+ var renderer = new rendering.StreamRenderer(asap, callback, context || {});
+ renderer.stream.pipe(output);
+ if (names)
+ renderer.start(names);
+ return renderer;
+};
+
+exports.renderString = function(names, context, callback) {
+ // callback signature: function(err, string)
+ // can I force it to be sync? callback is okay too, if not
+ var renderer = new rendering.StringRenderer(false, callback, context);
+ renderer.start(names);
+ return renderer;
+};
View
@@ -4,7 +4,7 @@ var fs = require('fs'),
Buffer = require('buffer').Buffer;
var ROOT = process.cwd();
-// Items in the cache are keyed by filepath, relative to ROOT or absolute,
+// Items in the cache are keyed by filepath, relative to ROOT or absolute,
// based on whether the given filepath starts with a '/' or not.
var CACHE = {};
// Compiles a file. The result will be cached as the filename and can be
@@ -13,7 +13,7 @@ var parseTemplate = exports.parseTemplate = function(name, template_string) {
CACHE[name] = new Parser(template_string).tokens;
};
var SETTINGS = {};
-// Hits the in-Node cache to see if the template exists. If it does, this'll
+// Hits the in-Node cache to see if the template exists. If it does, this'll
// call the callback pretty quickly, but if there's a cache miss, it'll have
// to read the file and then parse it (compileFilename).
exports.hitCache = function(name) {
@@ -107,7 +107,7 @@ var Parser = function(template_string, options) {
break;
}
}
-
+
if (this.stack.length > 1) {
// console.warn(util.inspect(this.tokens, false, null))
console.warn("Some section(s) were not closed (outermost first):");
@@ -153,15 +153,15 @@ Parser.prototype = {
if (index === -1) {
throw new Error('Encountered an unclosed tag. ' + this.buffer_string + ' should contain ' + this.close_tag + '.');
}
-
+
var raw = this.buffer_string.substring(0, index);
var tag = raw.replace(/^\s+|\s+$/g, ''); // strip all edge whitespace
var close_tag_length = this.close_tag.length; // silly hack for }}} closing tags
// node.t is a string; e.g. 'escaped', 'unescaped', 'partial', 'section', etc.
// node.val (optional, highly recommended) is a string, which must be an object in the context, possibly a function.
// node.block (optional) is a list of nodes
- // node.arguments (optional) is a list of dicts, e.g.
+ // node.arguments (optional) is a list of dicts, e.g.
// {t: "static"|"variable", val: "six"}, potentially empty/undefined.
var new_node, top = this.stackTop();
@@ -182,7 +182,7 @@ Parser.prototype = {
this.setTags(parts[0], parts[1]);
} else if (tag[0] === '#') {
new_node = {t: 'section', val: tag.slice(1)};
- this.stack.push([]);
+ this.stack.push([]);
} else if (tag[0] === '^') {
new_node = {t: 'inverted_section', val: tag.slice(1)};
this.stack.push([]);
@@ -199,9 +199,10 @@ Parser.prototype = {
} else if (tag[0] === '!') {
// nothing
} else {
- console.error("The tag '" + tag + "' is not recognized mustache/amulet syntax.");
+ console.error("The tag '" + tag + "' is not recognized mustache/amulet syntax. ");
+ console.log(util.inspect(this.tokens, true, null));
}
-
+
if (new_node !== undefined) {
if (new_node.val) {
@@ -213,7 +214,7 @@ Parser.prototype = {
// by using the syntax {{#results -> result}}, we can require that it is accessible as context.result
new_node.subsection = new_node.val.slice(section_match.index + section_match[0].length);
// console.log("Setting subsection to", new_node.subsection);
- new_node.val = new_node.val.slice(0, section_match.index)
+ new_node.val = new_node.val.slice(0, section_match.index);
}
}
@@ -223,10 +224,10 @@ Parser.prototype = {
// xxx: support chaining!
// xxx: support pulling out of context if eval throws an error or returns undefined
new_node.filter = eval(new_node.val.slice(pipe_match.index + pipe_match[0].length));
- new_node.val = new_node.val.slice(0, pipe_match.index)
+ new_node.val = new_node.val.slice(0, pipe_match.index);
}
- // open parens indicates function application,
+ // open parens indicates function application,
// the entire following conditional is for functional application.
var open_parens_index = new_node.val.indexOf('(');
if (open_parens_index > -1) {
@@ -250,25 +251,25 @@ Parser.prototype = {
}
return {t: type, val: trimmed_val};
});
-
+
new_node.val = new_node.val.slice(0, open_parens_index);
- new_node.arguments = argument_array;
+ new_node['arguments'] = argument_array;
}
}
top.push(new_node);
}
// todo: syntax for "never wait even if mode is asap"
// (that is, act like asap=false for this variable, even if asap=true at the renderer level)
-
+
this.buffer_string = this.buffer_string.substring(index + close_tag_length);
this.state = 'raw'; // send to scanMustache
},
postProcess: function() {
// operates on this.tokens in place.
function walk(tokens) {
for (var k = 0; k < tokens.length; k++) {
-
+
}
}
walk(this.tokens);
View
@@ -0,0 +1,36 @@
+var base_proto = ({}).__proto__;
+// base_proto.__proto__ === null
+
+exports.push = function(object, new_proto) {
+ // truncate the object to it's top properties if it doesn't have a __depth indicator
+ object.__depth = object.__depth || 0;
+ // don't store the object(.__proto__)+ that gets replaced, since we're assuming it === base_proto
+ switch (object.__depth) {
+ case 0: object.__proto__ = new_proto; break;
+ case 1: object.__proto__.__proto__ = new_proto; break;
+ case 2: object.__proto__.__proto__.__proto__ = new_proto; break;
+ case 3: object.__proto__.__proto__.__proto__.__proto__ = new_proto; break;
+ case 4: object.__proto__.__proto__.__proto__.__proto__.__proto__ = new_proto; break;
+ case 5: object.__proto__.__proto__.__proto__.__proto__.__proto__.__proto__ = new_proto; break;
+ case 6: object.__proto__.__proto__.__proto__.__proto__.__proto__.__proto__.__proto__ = new_proto; break;
+ case 7: object.__proto__.__proto__.__proto__.__proto__.__proto__.__proto__.__proto__.__proto__ = new_proto; break;
+ default: console.log("pushProto doesn't handle protos that deep. Sry!"); break;
+ }
+ object.__depth++;
+};
+
+exports.pop = function(object) {
+ switch (object.__depth) {
+ case 0: console.error("Cannot popProto an object with __depth == 0"); break;
+ case 1: object.__proto__ = base_proto; break;
+ case 2: object.__proto__.__proto__ = base_proto; break;
+ case 3: object.__proto__.__proto__.__proto__ = base_proto; break;
+ case 4: object.__proto__.__proto__.__proto__.__proto__ = base_proto; break;
+ case 5: object.__proto__.__proto__.__proto__.__proto__.__proto__ = base_proto; break;
+ case 6: object.__proto__.__proto__.__proto__.__proto__.__proto__.__proto__ = base_proto; break;
+ case 7: object.__proto__.__proto__.__proto__.__proto__.__proto__.__proto__.__proto__ = base_proto; break;
+ case 8: object.__proto__.__proto__.__proto__.__proto__.__proto__.__proto__.__proto__.__proto__ = base_proto; break;
+ default: console.log("popProto doesn't handle protos that deep."); break;
+ }
+ object.__depth--;
+};
Oops, something went wrong.

0 comments on commit 6cfc22b

Please sign in to comment.