First pass at getting booleans working

This commit is contained in:
wycats
2010-07-31 18:26:26 -07:00
parent 755f854c50
commit 8714a581e9
2 changed files with 97 additions and 21 deletions
+82 -17
View File
@@ -1,7 +1,12 @@
Handlebars = {
compile: function(string) {
var compiler = new Handlebars.Compiler(string);
return compiler.compile();
var result = compiler.compile();
return new Function("context", result);
},
isFunction: function(fn) {
return toString.call(fn) === "[object Function]";
}
}
@@ -10,15 +15,31 @@ Handlebars.Compiler = function(string) {
this.pointer = -1;
this.mustache = false;
this.text = "";
this.fn = "var out = ''; ";
this.fn = "var out = ''; var lookup; ";
this.newlines = "";
this.comment = false;
}
Handlebars.catchAll = function(object, fn) {
var ret = "";
if(object === true) {
return fn(this);
} else if(object === false) {
return "";
} else if(toString.call(object) === "[object Array]") {
for(var i=0, j=object.length; i<j; i++) {
ret = ret + fn(object[i]);
}
return ret;
}
};
Handlebars.Compiler.prototype = {
getChar: function() {
this.pointer++;
return this.string[this.pointer];
getChar: function(n) {
var ret = this.peek(n);
this.pointer = this.pointer + (n || 1);
return ret;
},
peek: function(n) {
@@ -27,10 +48,9 @@ Handlebars.Compiler.prototype = {
return this.string.slice(start, start + n);
},
compile: function() {
compile: function(endCondition) {
var chr;
while(chr = this.getChar()) {
// entering mustache state
if(chr === "{" && this.peek() === "{" && !this.mustache) {
this.getChar();
this.parseMustache();
@@ -42,24 +62,41 @@ Handlebars.Compiler.prototype = {
}
this.text = this.text + chr;
}
if(endCondition && endCondition(this)) { break };
}
this.fn = this.fn + "\nreturn out;";
return new Function("context", this.fn);
this.addText();
return this.fn + "return out;";
},
addText: function() {
if(this.text) {
this.fn = this.fn + "out = out + '" + this.text + "'; ";
this.fn = this.fn + this.newlines;
this.newlines = ""
this.text = ""
}
},
addExpression: function(mustache) {
this.fn = this.fn + "out = out + context['" + mustache + "']; ";
},
parseMustache: function() {
var chr, mustache;
if(this.peek() === "!") {
var next = this.peek();
if(next === "!") {
this.comment = true;
this.getChar();
} else if(next === "#") {
this.openBlock = true;
this.getChar();
}
this.fn = this.fn + "out = out + '" + this.text + "'; ";
this.fn = this.fn + this.newlines;
this.newlines = ""
this.text = ""
this.addText();
this.mustache = " ";
while(chr = this.getChar()) {
@@ -67,9 +104,36 @@ Handlebars.Compiler.prototype = {
mustache = this.mustache.trim();
this.mustache = false;
this.getChar();
if(this.comment) { this.comment = false; return; }
this.fn = this.fn + "out = out + context['" + mustache + "']; ";
return;
if(this.comment) {
this.comment = false;
return;
} else if(this.openBlock) {
var compiler = new Handlebars.Compiler(this.string.slice(this.pointer + 1, -1));
// compile with a custom EOF instruction
var result = compiler.compile(function(compiler) {
if(compiler.peek(mustache.length + 5) === "{{/" + mustache + "}}") {
compiler.getChar(mustache.length + 5);
return true;
}
});
this.pointer += compiler.pointer + 1;
// each function made internally needs a unique IDs. These are locals, so they
// don't need to be globally unique, just per compiler
var fnId = "fn" + this.pointer.toString();
this.fn += "var " + fnId + " = function(context) {" + result + "}; ";
this.fn += "lookup = context['" + mustache + "']; ";
this.fn += "if(Handlebars.isFunction(lookup)) out = out + " + fnId + "(lookup); "
this.fn += "else if(typeof lookup !== 'undefined') out = out + Handlebars.catchAll(lookup, " + fnId + "); "
this.openBlock = false;
return;
} else {
this.addExpression(mustache);
return;
}
} else if(this.comment) {
;
} else {
@@ -78,3 +142,4 @@ Handlebars.Compiler.prototype = {
}
}
}
+15 -4
View File
@@ -1,17 +1,28 @@
module("basic context");
test("compiling with a basic context", function() {
var string = "Goodbye\n{{cruel}}\n{{world}}";
var string = "Goodbye\n{{cruel}}\n{{world}}!";
var template = Handlebars.compile(string);
result = template({cruel: "cruel", world: "world"});
equal("Goodbye\ncruel\nworld", result, "it works if all the required keys are provided");
equal(result, "Goodbye\ncruel\nworld!", "it works if all the required keys are provided");
});
test("comments", function() {
var string = "{{! Goodbye}}Goodbye\n{{cruel}}\n{{world}}";
var string = "{{! Goodbye}}Goodbye\n{{cruel}}\n{{world}}!";
var template = Handlebars.compile(string);
result = template({cruel: "cruel", world: "world"});
equal("Goodbye\ncruel\nworld", result, "it works if all the required keys are provided");
equal("Goodbye\ncruel\nworld!", result, "it works if all the required keys are provided");
});
test("boolean", function() {
var string = "{{#goodbye}}GOODBYE {{/goodbye}}cruel {{world}}!"
var template = Handlebars.compile(string);
result = template({goodbye: true, world: "world"});
equal("GOODBYE cruel world!", result, "booleans work when true");
result = template({goodbye: false, world: "world"});
equal("cruel world!", result, "booleans work when true");
});