Add support for block hashes and clean up mustache/program code

This commit is contained in:
tomhuda
2011-03-04 15:10:22 -08:00
parent ca9b9671a5
commit 357710f136
2 changed files with 59 additions and 51 deletions
+44 -45
View File
@@ -139,6 +139,12 @@ Handlebars.JavaScriptCompiler = function() {};
this.pushParams(params);
if(mustache.hash) {
this.hash(mustache.hash);
} else {
this.opcode('push', '{}');
}
// ID lookup is now on the stack
this.ID(mustache.id);
@@ -485,69 +491,62 @@ Handlebars.JavaScriptCompiler = function() {};
},
invokeMustache: function(paramSize, original) {
var params = ["context"], fn, slot;
fn = this.popStack();
var hash = this.popStack();
for(var i=0; i<paramSize; i++) {
params.push(this.popStack());
}
this.register('tmp1', '{hash: ' + hash + '}');
if(this.data) {
this.source.push('tmp1.data = data');
}
params.push('tmp1');
var paramString = params.join(", ");
var helperMissing = ["context"].concat(this.quotedString(original)).concat(params.slice(1));
slot = this.nextStack();
if(paramSize === 0) {
// TODO: This case is not listed in the mustache spec. Is it important?
this.source.push("if(typeof " + fn + " === 'function') { " + slot + " = " + fn + ".call(" + paramString + "); } else { " + slot + " = " + fn + "; }");
} else {
this.source.push("if(typeof " + fn + " === 'function') { " + slot + " = " + fn + ".call(" + paramString + "); } else { " + slot + " = helpers.helperMissing.call(" + helperMissing + ") }");
}
this.populateParams(paramSize, this.quotedString(original), "{}", null, function(nextStack, helperMissingString, id) {
this.source.push("else if(" + id + "=== undefined) { " + nextStack + " = helpers.helperMissing.call(" + helperMissingString + "); }");
this.source.push("else { " + nextStack + " = " + id + "; }");
});
},
invokeProgram: function(guid, paramSize) {
var inverse = this.programExpression(this.inverse);
var mainProgram = this.programExpression(guid);
var fn = this.popStack();
var id = fn;
this.populateParams(paramSize, null, mainProgram, inverse, function(nextStack, helperMissingString, id) {
this.source.push("else { " + nextStack + " = helpers.blockHelperMissing.call(" + helperMissingString + "); }");
});
},
var params = ["context"];
var blockMissingParams = ["context", id];
populateParams: function(paramSize, helperId, program, inverse, fn) {
var id = this.popStack(), nextStack;
var params = [];
var hash = this.popStack();
for(var i=0; i<paramSize; i++) {
var param = this.popStack();
params.push(param);
blockMissingParams.push(param);
}
var mainProgram = this.programExpression(guid);
this.register('tmp1', program);
this.source.push('tmp1.hash = ' + hash + ';');
params.push(mainProgram, inverse);
blockMissingParams.push(mainProgram, inverse);
if(inverse) {
this.source.push('tmp1.fn = tmp1;');
this.source.push('tmp1.inverse = ' + inverse + ';');
}
if(this.data) {
this.register('tmp1', '{data: data}');
params.push("tmp1");
params.push("tmp1");
blockMissingParams.push("tmp1");
this.source.push('tmp1.data = data;');
}
var nextStack = this.nextStack();
params.push('tmp1');
this.source.push("if(typeof " + id + " === 'function') { " + nextStack + " = " + id + ".call(" + params.join(", ") + "); }");
this.source.push("else { " + nextStack + " = helpers.blockHelperMissing.call(" + blockMissingParams.join(", ") + "); }");
// TODO: This is legacy behavior. Deprecate and remove.
if(inverse) {
params.push(inverse);
}
this.populateCall(params, id, helperId || id, fn);
},
populateCall: function(params, id, helperId, fn) {
var paramString = ["context"].concat(params).join(", ");
var helperMissingString = ["context"].concat(helperId).concat(params).join(", ");
nextStack = this.nextStack();
this.source.push("if(typeof " + id + " === 'function') { " + nextStack + " = " + id + ".call(" + paramString + "); }");
fn.call(this, nextStack, helperMissingString, id);
},
invokeInverse: function(guid) {
+15 -6
View File
@@ -576,12 +576,12 @@ test("passing in data to a compiled function that expects data - works with bloc
equals("happy world?", result);
});
test("passing in data to a compiled function that expects data - works with block helpers that use ..", function() {
test("passing in data to a compiled function that expects data - data is passed to with block helpers where children use ..", function() {
var template = Handlebars.compile("{{#hello}}{{world ../zomg}}{{/hello}}", true);
var helpers = {
hello: function(fn, inverse, options) {
return options.data.accessData + " " + fn({exclaim: "?"});
hello: function(fn, inverse) {
return fn.data.accessData + " " + fn({exclaim: "?"});
},
world: function(thing, options) {
return options.data.adjective + " " + thing + (this.exclaim || "");
@@ -684,6 +684,15 @@ test("helpers can take an optional hash", function() {
equals(result, "GOODBYE CRUEL WORLD");
});
// test("helpers can take an optional hash", function() {
// var template = Handlebars.compile('{{#goodbye cruel="CRUEL"}}world{{/goodbye}}')
// });
test("block helpers can take an optional hash", function() {
var template = Handlebars.compile('{{#goodbye cruel="CRUEL"}}world{{/goodbye}}');
var helpers = {
goodbye: function(options) {
return "GOODBYE " + options.hash.cruel + " " + options.fn(this);
}
};
var result = template({}, helpers);
equals(result, "GOODBYE CRUEL world");
});