diff --git a/README.md b/README.md
index ea74fc83..5616bfc2 100644
--- a/README.md
+++ b/README.md
@@ -419,6 +419,29 @@ Mustache.render(template, view, {
});
```
+Partials can have dynamic names, which begin with `*`. In this case, a value is read from the context and the partial with that value is used.
+
+For example, this template and partial:
+
+ base.mustache:
+
Message of the Day
+ {{> *dayOfWeek}}
+
+ thursday.mustache:
+ This must be Thursday. I never could get the hang of Thursdays.
+
+When loaded with the context:
+```json
+{
+ "dayOfWeek": "thursday"
+}
+```
+will be expanded to:
+```html
+ Message of the Day
+ This must be Thursday. I never could get the hang of Thursdays.
+```
+
### Custom Delimiters
Custom delimiters can be used in place of `{{` and `}}` by setting the new values in JavaScript or in templates.
diff --git a/mustache.js b/mustache.js
index ed0cd6d7..42b5fd36 100644
--- a/mustache.js
+++ b/mustache.js
@@ -79,6 +79,7 @@ var spaceRe = /\s+/;
var equalsRe = /\s*=/;
var curlyRe = /\s*\}/;
var tagRe = /#|\^|\/|>|\{|&|=|!/;
+var dynamicRe = /\*/;
/**
* Breaks up the given `template` string into a tree of tokens. If the `tags`
@@ -202,6 +203,14 @@ function parseTemplate (template, tags) {
scanner.scan(curlyRe);
scanner.scanUntil(closingTagRe);
type = '&';
+ } else if (type === '>') {
+ if (scanner.scan(dynamicRe) === '') {
+ value = scanner.scanUntil(closingTagRe);
+ } else {
+ scanner.scan(whiteRe);
+ type = '>*';
+ value = scanner.scanUntil(closingTagRe);
+ }
} else {
value = scanner.scanUntil(closingTagRe);
}
@@ -210,7 +219,7 @@ function parseTemplate (template, tags) {
if (!scanner.scan(closingTagRe))
throw new Error('Unclosed tag at ' + scanner.pos);
- if (type == '>') {
+ if (type == '>' || type == '>*') {
token = [ type, value, start, scanner.pos, indentation, tagIndex, lineHasNonSpace ];
} else {
token = [ type, value, start, scanner.pos ];
@@ -571,6 +580,7 @@ Writer.prototype.renderTokens = function renderTokens (tokens, context, partials
if (symbol === '#') value = this.renderSection(token, context, partials, originalTemplate, config);
else if (symbol === '^') value = this.renderInverted(token, context, partials, originalTemplate, config);
else if (symbol === '>') value = this.renderPartial(token, context, partials, config);
+ else if (symbol === '>*') value = this.renderDynamicPartial(token, context, partials, config);
else if (symbol === '&') value = this.unescapedValue(token, context);
else if (symbol === 'name') value = this.escapedValue(token, context, config);
else if (symbol === 'text') value = this.rawValue(token);
@@ -636,10 +646,27 @@ Writer.prototype.indentPartial = function indentPartial (partial, indentation, l
return partialByNl.join('\n');
};
-Writer.prototype.renderPartial = function renderPartial (token, context, partials, config) {
+Writer.prototype.renderDynamicPartial = function renderPartial (token, context, partials, config) {
if (!partials) return;
var tags = this.getConfigTags(config);
+ var name = context.lookup(token[1].trim());
+ var value = isFunction(partials) ? partials(name) : partials[name];
+ if (value != null) {
+ var lineHasNonSpace = token[6];
+ var tagIndex = token[5];
+ var indentation = token[4];
+ var indentedValue = value;
+ if (tagIndex == 0 && indentation) {
+ indentedValue = this.indentPartial(value, indentation, lineHasNonSpace);
+ }
+ var tokens = this.parse(indentedValue, tags);
+ return this.renderTokens(tokens, context, partials, indentedValue, config);
+ }
+};
+Writer.prototype.renderPartial = function renderPartial (token, context, partials, config) {
+ if (!partials) return;
+ var tags = this.getConfigTags(config);
var value = isFunction(partials) ? partials(token[1]) : partials[token[1]];
if (value != null) {
var lineHasNonSpace = token[6];
diff --git a/test/mustache-spec-test.js b/test/mustache-spec-test.js
index 0e500189..d035048b 100644
--- a/test/mustache-spec-test.js
+++ b/test/mustache-spec-test.js
@@ -14,6 +14,9 @@ var skipTests = {
inverted: [
'Standalone Without Newline'
],
+ interpolation: [
+ 'Dotted Names - Context Precedence'
+ ],
partials: [
'Standalone Without Previous Line',
'Standalone Without Newline'
@@ -21,6 +24,34 @@ var skipTests = {
sections: [
'Standalone Without Newline'
],
+ '~inheritance': [
+ 'Default',
+ 'Variable',
+ 'Triple Mustache',
+ 'Sections',
+ 'Negative Sections',
+ 'Mustache Injection',
+ 'Inherit',
+ 'Overridden content',
+ 'Data does not override block',
+ 'Data does not override block default',
+ 'Overridden parent',
+ 'Two overridden parents',
+ 'Override parent with newlines',
+ 'Inherit indentation',
+ 'Only one override',
+ 'Parent template',
+ 'Recursion',
+ 'Multi-level inheritance',
+ 'Multi-level inheritance, no sub child',
+ 'Text inside parent',
+ 'Block scope',
+ 'Standalone parent',
+ 'Standalone block',
+ 'Block reindentation',
+ 'Intrinsic indentation',
+ 'Nested block reindentation'
+ ],
'~lambdas': [
'Interpolation',
'Interpolation - Expansion',
diff --git a/test/parse-test.js b/test/parse-test.js
index 1fb2cabe..547520b7 100644
--- a/test/parse-test.js
+++ b/test/parse-test.js
@@ -46,6 +46,10 @@ var expectations = {
' {{> abc }}\n' : [ [ '>', 'abc', 2, 12, ' ', 0, false ] ],
' {{> abc }} {{> abc }}\n' : [ [ '>', 'abc', 2, 12, ' ', 0, false ], [ '>', 'abc', 13, 23, ' ', 1, false ] ],
'{{ > abc }}' : [ [ '>', 'abc', 0, 11, '', 0, false ] ],
+ '{{>*abc}}' : [ [ '>*', 'abc', 0, 9, '', 0, false ] ],
+ '{{> *abc}}' : [ [ '>*', 'abc', 0, 10, '', 0, false ] ],
+ '{{>* abc}}' : [ [ '>*', 'abc', 0, 10, '', 0, false ] ],
+ '{{ > * abc }}' : [ [ '>*', 'abc', 0, 13, '', 0, false ] ],
'{{=<% %>=}}' : [ [ '=', '<% %>', 0, 11 ] ],
'{{= <% %> =}}' : [ [ '=', '<% %>', 0, 13 ] ],
'{{=<% %>=}}<%={{ }}=%>' : [ [ '=', '<% %>', 0, 11 ], [ '=', '{{ }}', 11, 22 ] ],
diff --git a/test/partial-test.js b/test/partial-test.js
index 54d62b58..55f8d0de 100644
--- a/test/partial-test.js
+++ b/test/partial-test.js
@@ -172,4 +172,18 @@ describe('Partials spec', function () {
var renderResult = Mustache.render(template, {}, partials, tags);
assert.equal(renderResult, expected);
});
+
+ describe('when rendering a dynamically named partial after already having rendered that partial with a different name value', function () {
+ it('returns different output for the latter render', function () {
+ var template = 'Place: {{>*place}}';
+ var partials = {
+ first: '1st',
+ second: '2nd',
+ };
+ var renderedFirst = Mustache.render(template, {place:'first'}, partials);
+ var renderedSecond = Mustache.render(template, {place:'second'}, partials);
+
+ assert.notEqual(renderedFirst, renderedSecond);
+ });
+ });
});
diff --git a/test/spec b/test/spec
index 72233f3f..7138576e 160000
--- a/test/spec
+++ b/test/spec
@@ -1 +1 @@
-Subproject commit 72233f3ffda9e33915fd3022d0a9ebbcce265acd
+Subproject commit 7138576e12ff0f05511de77807c2fb3959bb22e3