Add support for passing String parameters to helper

This commit is contained in:
tomhuda
2011-03-30 23:12:45 -07:00
parent 2615fa4bd1
commit 9333d1210d
3 changed files with 134 additions and 31 deletions
+2 -1
View File
@@ -60,7 +60,7 @@ var Handlebars = require("handlebars");
Handlebars.AST.IdNode = function(parts) {
this.type = "ID";
this.original = parts.join("/");
this.original = parts.join(".");
var dig = [], depth = 0;
@@ -73,6 +73,7 @@ var Handlebars = require("handlebars");
}
this.parts = dig;
this.string = dig.join('.');
this.depth = depth;
this.isSimple = (dig.length === 1) && (depth === 0);
};
+48 -23
View File
@@ -20,7 +20,8 @@ Handlebars.JavaScriptCompiler = function() {};
invokePartial: 12,
push: 13,
invokeInverse: 14,
assignToHash: 15
assignToHash: 15,
pushStringParam: 16
};
Compiler.MULTI_PARAM_OPCODES = {
@@ -36,7 +37,8 @@ Handlebars.JavaScriptCompiler = function() {};
invokePartial: 1,
push: 1,
invokeInverse: 1,
assignToHash: 1
assignToHash: 1,
pushStringParam: 1
};
Compiler.DISASSEMBLE_MAP = {};
@@ -89,9 +91,10 @@ Handlebars.JavaScriptCompiler = function() {};
guid: 0,
compile: function(program) {
compile: function(program, options) {
this.children = [];
this.depths = {list: []};
this.options = options || {};
return this.program(program);
},
@@ -116,7 +119,7 @@ Handlebars.JavaScriptCompiler = function() {};
},
compileProgram: function(program) {
var result = new Compiler().compile(program);
var result = new Compiler().compile(program, this.options);
var guid = this.guid++;
this.usePartial = this.usePartial || result.usePartial;
@@ -227,7 +230,17 @@ Handlebars.JavaScriptCompiler = function() {};
while(i--) {
param = params[i];
this[param.type](param);
if(this.options.stringParams) {
if(param.depth) {
this.addDepth(param.depth);
}
this.opcode('getContext', param.depth || 0);
this.opcode('pushStringParam', param.string);
} else {
this[param.type](param);
}
}
},
@@ -289,9 +302,9 @@ Handlebars.JavaScriptCompiler = function() {};
},
// END PUBLIC API
compile: function(environment, data) {
compile: function(environment, options) {
this.environment = environment;
this.data = data;
this.options = options || {};
this.preamble();
@@ -299,7 +312,7 @@ Handlebars.JavaScriptCompiler = function() {};
this.stackVars = [];
this.registers = {list: []};
this.compileChildren(environment, data);
this.compileChildren(environment, options);
Handlebars.log(Handlebars.logger.DEBUG, environment.disassemble() + "\n\n");
@@ -393,13 +406,12 @@ Handlebars.JavaScriptCompiler = function() {};
var params = ["Handlebars", "context", "helpers", "partials"];
if(this.data) { params.push("data"); }
if(this.options.data) { params.push("data"); }
for(var i=0, l=this.environment.depths.list.length; i<l; i++) {
params.push("depth" + this.environment.depths.list[i]);
}
if(params.length === 4 && !this.environment.usePartial) { params.pop(); }
params.push(this.source.join("\n"));
@@ -477,6 +489,11 @@ Handlebars.JavaScriptCompiler = function() {};
this.source.push(topStack + " = " + this.nameLookup(topStack, name, 'context') + ";");
},
pushStringParam: function(string) {
this.pushStack("currentContext");
this.pushString(string);
},
pushString: function(string) {
this.pushStack(this.quotedString(string));
},
@@ -503,24 +520,32 @@ Handlebars.JavaScriptCompiler = function() {};
populateParams: function(paramSize, helperId, program, inverse, fn) {
var id = this.popStack(), nextStack;
var params = [];
var params = [], param, stringParam;
var hash = this.popStack();
for(var i=0; i<paramSize; i++) {
var param = this.popStack();
params.push(param);
}
this.register('tmp1', program);
this.source.push('tmp1.hash = ' + hash + ';');
if(this.options.stringParams) {
this.source.push('tmp1.contexts = [];');
}
for(var i=0; i<paramSize; i++) {
param = this.popStack();
params.push(param);
if(this.options.stringParams) {
this.source.push('tmp1.contexts.push(' + this.popStack() + ');');
}
}
if(inverse) {
this.source.push('tmp1.fn = tmp1;');
this.source.push('tmp1.inverse = ' + inverse + ';');
}
if(this.data) {
if(this.options.data) {
this.source.push('tmp1.data = data;');
}
@@ -566,7 +591,7 @@ Handlebars.JavaScriptCompiler = function() {};
compiler: JavaScriptCompiler,
compileChildren: function(environment, data) {
compileChildren: function(environment, options) {
var children = environment.children, child, compiler;
var compiled = [];
@@ -574,7 +599,7 @@ Handlebars.JavaScriptCompiler = function() {};
child = children[i];
compiler = new this.compiler();
compiled[i] = compiler.compile(child, data);
compiled[i] = compiler.compile(child, options);
}
environment.rawChildren = children;
@@ -588,7 +613,7 @@ Handlebars.JavaScriptCompiler = function() {};
var depths = this.environment.rawChildren[guid].depths.list;
if(this.data) { programParams.push("data"); }
if(this.options.data) { programParams.push("data"); }
for(var i=0, l = depths.length; i<l; i++) {
depth = depths[i];
@@ -681,10 +706,10 @@ Handlebars.VM = {
};
},
noop: function() { return ""; },
compile: function(string, data) {
compile: function(string, options) {
var ast = Handlebars.parse(string);
var environment = new Handlebars.Compiler().compile(ast);
return new Handlebars.JavaScriptCompiler().compile(environment, data);
var environment = new Handlebars.Compiler().compile(ast, options);
return new Handlebars.JavaScriptCompiler().compile(environment, options);
},
invokePartial: function(partial, name, context, helpers, partials) {
if(partial === undefined) {
+84 -7
View File
@@ -524,7 +524,7 @@ test("overriding property lookup", function() {
test("passing in data to a compiled function that expects data - works with helpers", function() {
var template = Handlebars.compile("{{hello}}", true);
var template = Handlebars.compile("{{hello}}", {data: true});
var helpers = {
hello: function(options) {
@@ -537,7 +537,7 @@ test("passing in data to a compiled function that expects data - works with help
});
test("passing in data to a compiled function that expects data - works with helpers and parameters", function() {
var template = Handlebars.compile("{{hello world}}", true);
var template = Handlebars.compile("{{hello world}}", {data: true});
var helpers = {
hello: function(noun, options) {
@@ -550,7 +550,7 @@ test("passing in data to a compiled function that expects data - works with help
});
test("passing in data to a compiled function that expects data - works with block helpers", function() {
var template = Handlebars.compile("{{#hello}}{{world}}{{/hello}}", true);
var template = Handlebars.compile("{{#hello}}{{world}}{{/hello}}", {data: true});
var helpers = {
hello: function(fn) {
@@ -566,7 +566,7 @@ test("passing in data to a compiled function that expects data - works with bloc
});
test("passing in data to a compiled function that expects data - works with block helpers that use ..", function() {
var template = Handlebars.compile("{{#hello}}{{world ../zomg}}{{/hello}}", true);
var template = Handlebars.compile("{{#hello}}{{world ../zomg}}{{/hello}}", {data: true});
var helpers = {
hello: function(fn) {
@@ -582,7 +582,7 @@ test("passing in data to a compiled function that expects data - works with bloc
});
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 template = Handlebars.compile("{{#hello}}{{world ../zomg}}{{/hello}}", {data: true});
var helpers = {
hello: function(fn, inverse) {
@@ -598,7 +598,7 @@ test("passing in data to a compiled function that expects data - data is passed
});
test("you can override inherited data when invoking a helper", function() {
var template = Handlebars.compile("{{#hello}}{{world zomg}}{{/hello}}", true);
var template = Handlebars.compile("{{#hello}}{{world zomg}}{{/hello}}", {data: true});
var helpers = {
hello: function(fn) {
@@ -615,7 +615,7 @@ test("you can override inherited data when invoking a helper", function() {
test("you can override inherited data when invoking a helper with depth", function() {
var template = Handlebars.compile("{{#hello}}{{world ../zomg}}{{/hello}}", true);
var template = Handlebars.compile("{{#hello}}{{world ../zomg}}{{/hello}}", {data: true});
var helpers = {
hello: function(fn) {
@@ -701,3 +701,80 @@ test("block helpers can take an optional hash", function() {
var result = template({}, helpers);
equals(result, "GOODBYE CRUEL world");
});
test("arguments to helpers can be retrieved from options hash in string form", function() {
var template = Handlebars.compile('{{wycats is.a slave.driver}}', {stringParams: true});
var helpers = {
wycats: function(passiveVoice, noun, options) {
return "HELP ME MY BOSS " + passiveVoice + ' ' + noun;
}
};
var result = template({}, helpers);
equals(result, "HELP ME MY BOSS is.a slave.driver");
});
test("when using block form, arguments to helpers can be retrieved from options hash in string form", function() {
var template = Handlebars.compile('{{#wycats is.a slave.driver}}help :({{/wycats}}', {stringParams: true});
var helpers = {
wycats: function(passiveVoice, noun, options) {
return "HELP ME MY BOSS " + passiveVoice + ' ' +
noun + ': ' + options.fn(this);
}
};
var result = template({}, helpers);
equals(result, "HELP ME MY BOSS is.a slave.driver: help :(");
});
test("when inside a block in String mode, .. passes the appropriate context in the options hash", function() {
var template = Handlebars.compile('{{#with dale}}{{tomdale ../need dad.joke}}{{/with}}', {stringParams: true});
var helpers = {
tomdale: function(desire, noun, options) {
return "STOP ME FROM READING HACKER NEWS I " +
options.contexts[0][desire] + " " + noun;
},
"with": function(context, options) {
return options.fn(options.contexts[0][context]);
}
};
var result = template({
dale: {},
need: 'need-a'
}, helpers);
equals(result, "STOP ME FROM READING HACKER NEWS I need-a dad.joke");
});
test("when inside a block in String mode, .. passes the appropriate context in the options hash to a block helper", function() {
var template = Handlebars.compile('{{#with dale}}{{#tomdale ../need dad.joke}}wot{{/tomdale}}{{/with}}', {stringParams: true});
var helpers = {
tomdale: function(desire, noun, options) {
return "STOP ME FROM READING HACKER NEWS I " +
options.contexts[0][desire] + " " + noun + " " +
options.fn(this);
},
"with": function(context, options) {
return options.fn(options.contexts[0][context]);
}
};
var result = template({
dale: {},
need: 'need-a'
}, helpers);
equals(result, "STOP ME FROM READING HACKER NEWS I need-a dad.joke wot");
});