fix argument binding with dots in Spacebars.index

This commit is contained in:
David Greenspan
2013-10-07 10:45:13 -07:00
parent 3f93c386ce
commit 84873c8a22
4 changed files with 80 additions and 14 deletions

View File

@@ -91,3 +91,7 @@
content
{{/if}}
</template>
<template name="spacebars_template_test_block_helper_dotted_arg">
{{#foo bar.baz qux}}{{/foo}}
</template>

View File

@@ -301,3 +301,58 @@ Tinytest.add("spacebars - templates - block helper component with three helper a
Deps.flush();
test.equal(div.innerHTML.trim(), "");
});
Tinytest.add("spacebars - templates - block helper with dotted arg", function (test) {
var tmpl = Template.spacebars_template_test_block_helper_dotted_arg;
var R1 = ReactiveVar(1);
var R2 = ReactiveVar(10);
var R3 = ReactiveVar(100);
var initCount = 0;
tmpl.foo = Template.spacebars_template_test_bracketed_this.extend({
init: function () { initCount++; }
});
tmpl.bar = function () {
return {
r1: R1.get(),
baz: function (r3) {
return this.r1 + R2.get() + r3;
}
};
};
tmpl.qux = function () { return R3.get(); };
var div = renderToDiv(tmpl);
test.equal(div.innerHTML, "[111]");
test.equal(initCount, 1);
R1.set(2);
Deps.flush();
test.equal(div.innerHTML, "[112]");
test.equal(initCount, 1);
R2.set(20);
Deps.flush();
test.equal(div.innerHTML, "[122]");
test.equal(initCount, 1);
R3.set(200);
Deps.flush();
test.equal(div.innerHTML, "[222]");
test.equal(initCount, 1);
R2.set(30);
Deps.flush();
test.equal(div.innerHTML, "[232]");
test.equal(initCount, 1);
R1.set(3);
Deps.flush();
test.equal(div.innerHTML, "[233]");
test.equal(initCount, 1);
R3.set(300);
Deps.flush();
test.equal(div.innerHTML, "[333]");
test.equal(initCount, 1);
});

View File

@@ -938,21 +938,19 @@ Spacebars.compile = function (inputString, options) {
// of `foo.bar.baz` that allows safe indexing of `null` and
// indexing of functions to get other functions.
//
// `foo` must be one of three types of values, and the return value
// is also one of these three types:
// * Falsy values
// * Non-functions (i.e. constants)
// * Fully "bound" functions, which take no arguments and ignore `this`
// In `Spacebars.index(foo, "bar")`, `foo` is assumed to be either
// a non-function value or a "fully-bound" function wrapping a value,
// taking no arguments and ignoring `this`.
//
// `Spacebars.index("foo", bar)` behaves as follows:
// `Spacebars.index(foo, "bar")` behaves as follows:
//
// * If `foo` is falsy, `foo` is returned.
//
// * If either `foo` is a function or `foo.bar` is, then a new
// fully-bound function is returned that, when called, will calculate
// a "safe" version of `foo().bar()`, where "dot" on a falsy value
// just returns the falsy value, and function calls are a no-op on
// non-functions.
// function is returned that, when called on arguments `args...`,
// calculates a "safe" version of `foo().bar(args...)`,
// where "dot" on a falsy value just returns the falsy value,
// and function calls are a no-op on non-functions.
//
// * Otherwise, the non-function `foo.bar` is returned.
Spacebars.index = function (value, id1/*, id2, ...*/) {
@@ -973,19 +971,19 @@ Spacebars.index = function (value, id1/*, id2, ...*/) {
var result = value[id1];
if (typeof result !== 'function')
return result;
return function () {
return result.call(value);
return function (/*arguments*/) {
return result.apply(value, arguments);
};
}
return function () {
return function (/*arguments*/) {
var foo = value();
if (! foo)
return foo; // falsy, don't index, pass through
var bar = foo[id1];
if (typeof bar !== 'function')
return bar;
return bar.call(foo);
return bar.apply(foo, arguments);
};
};

View File

@@ -521,4 +521,13 @@ Tinytest.add("spacebars - Spacebars.index", function (test) {
test.equal(Spacebars.index(0, 'abc', 'def'), 0);
test.equal(Spacebars.index(function () { return null; }, 'abc', 'def')(), null);
test.equal(Spacebars.index(function () { return 0; }, 'abc', 'def')(), 0);
// test that in `foo.bar`, `bar` may be a function that takes arguments.
test.equal(Spacebars.index(
{ one: 1, inc: function (x) { return this.one + x; } }, 'inc')(6), 7);
test.equal(Spacebars.index(
function () {
return { one: 1, inc: function (x) { return this.one + x; } };
}, 'inc')(8), 9);
});