Skip to content

Commit

Permalink
Underscore 0.5.6, with custom template delimiters
Browse files Browse the repository at this point in the history
  • Loading branch information
jashkenas committed Jan 18, 2010
1 parent 94195e6 commit 7d9e603
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 52 deletions.
55 changes: 33 additions & 22 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,11 @@ <h2>Downloads <i style="padding-left: 12px; font-size:12px;">(Right-click, and u
<p>
<table>
<tr>
<td><a href="underscore.js">Development Version (0.5.5)</a></td>
<td><a href="underscore.js">Development Version (0.5.6)</a></td>
<td><i>22kb, Uncompressed with Comments</i></td>
</tr>
<tr>
<td><a href="underscore-min.js">Production Version (0.5.5)</a></td>
<td><a href="underscore-min.js">Production Version (0.5.6)</a></td>
<td><i>3kb, Packed and Gzipped</i></td>
</tr>
</table>
Expand Down Expand Up @@ -979,26 +979,20 @@ <h2>Utility Functions</h2>
</p>
<pre>
_.uniqueId('contact_');
=&gt; 'contact_104'
</pre>
=&gt; 'contact_104'</pre>

<p id="template">
<b class="header">template</b><code>_.template(templateString, [context])</code>
<br />
Compiles JavaScript templates into functions that can be evaluated
for rendering. Useful for rendering complicated bits of HTML from JSON
data sources. Template functions can both interpolate variables, using<br />
<i>&lt;%= &hellip; %&gt;</i>, as well as execute arbitrary JavaScript code, with
<i>&lt;% &hellip; %&gt;</i>. When you evaluate a template function, pass in a
<tt>&lt;%= &hellip; %&gt;</tt>, as well as execute arbitrary JavaScript code, with
<tt>&lt;% &hellip; %&gt;</tt>. When you evaluate a template function, pass in a
<b>context</b> object that has properties corresponding to the template's free
variables. If you're writing a one-off, you can pass the <b>context</b>
object as the second parameter to <b>template</b> in order to render
immediately instead of returning a template function.
<br />
If the <i>&lt;% &hellip; %&gt;</i> syntax is not convenient because
your templating languages assigns special meaning to it, the delimeters
can be customized by passing an object as the first argument. See the
code sample below for options.
</p>
<pre>
var compiled = _.template("hello: &lt;%= name %&gt;");
Expand All @@ -1007,17 +1001,28 @@ <h2>Utility Functions</h2>

var list = "&lt;% _.each(people, function(name) { %&gt; &lt;li&gt;&lt;%= name %&gt;&lt;/li&gt; &lt;% }); %&gt;";
_.template(list, {people : ['moe', 'curly', 'larry']});
=&gt; "&lt;li&gt;moe&lt;/li&gt;&lt;li&gt;curly&lt;/li&gt;&lt;li&gt;larry&lt;/li&gt;"

var custom = "{{ _.each(people, function(name) { }} &lt;li&gt;{{= name }}&lt;/li&gt; {{ }); }}";
_.template({
template: custom,
start: '{{', // the code start delimeter
end: '}}', // the code end delimeter
interpolate: /\{\{=(.+?)\}\}/g // a regex with 1 capture group for the var name
}, {people : ['moe', 'curly', 'larry']});
=&gt; "&lt;li&gt;moe&lt;/li&gt;&lt;li&gt;curly&lt;/li&gt;&lt;li&gt;larry&lt;/li&gt;"
</pre>
=&gt; "&lt;li&gt;moe&lt;/li&gt;&lt;li&gt;curly&lt;/li&gt;&lt;li&gt;larry&lt;/li&gt;"</pre>

<p>
If ERB-style delimiters aren't your cup of tea, you can change Underscore's
template settings to use different symbols to set off interpolated code.
Define <b>start</b> and <b>end</b> tokens, and an <b>interpolate</b> regex
to match expressions that should be evaluated and inserted. For example,
to perform
<a href="http://github.com/janl/mustache.js#readme">Mustache.js</a>
style templating:
</p>

<pre>
_.templateSettings = {
start : '{{',
end : '}}',
interpolate : /\{\{(.+?)\}\}/g
};

var template = _.template("Hello {{ name }}!");
template({name : "Mustache"});
=&gt; "Hello Mustache!"</pre>

<h2>Chaining</h2>

Expand Down Expand Up @@ -1079,6 +1084,12 @@ <h2>Links &amp; Suggested Reading</h2>

<h2>Change Log</h2>

<p>
<b class="header">0.5.6</b><br />
Customizable delimiters for <tt>_.template</tt>, contributed by
<a href="http://github.com/iamnoah">Noah Sloan</a>.
</p>

<p>
<b class="header">0.5.5</b><br />
Fix for a bug in MobileSafari's OOP-wrapper, with the arguments object.
Expand Down
33 changes: 20 additions & 13 deletions test/utility.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,23 +39,30 @@ $(document).ready(function() {
result = fancyTemplate({people : {moe : "Moe", larry : "Larry", curly : "Curly"}});
equals(result, "<ul><li>Moe</li><li>Larry</li><li>Curly</li></ul>", 'can run arbitrary javascript in templates');

var custom = _.template({
template: "<ul>{{ for (key in people) { }}<li>{{= people[key] }}</li>{{ } }}</ul>",
start: "{{", end: "}}",
interpolate: /\{\{=(.+?)\}\}/g
});
result = custom({people : {moe : "Moe", larry : "Larry", curly : "Curly"}});
equals(result, "<ul><li>Moe</li><li>Larry</li><li>Curly</li></ul>", 'can run arbitrary javascript in templates');

var quoteTemplate = _.template("It's its, not it's");
equals(quoteTemplate({}), "It's its, not it's");

var customQuote = _.template({
template: "It's its, not it's",
start: "{{", end: "}}",
interpolate: /\{\{=(.+?)\}\}/g
});
_.templateSettings = {
start : '{{',
end : '}}',
interpolate : /\{\{=(.+?)\}\}/g
};

var custom = _.template("<ul>{{ for (key in people) { }}<li>{{= people[key] }}</li>{{ } }}</ul>");
result = custom({people : {moe : "Moe", larry : "Larry", curly : "Curly"}});
equals(result, "<ul><li>Moe</li><li>Larry</li><li>Curly</li></ul>", 'can run arbitrary javascript in templates');

var customQuote = _.template("It's its, not it's");
equals(customQuote({}), "It's its, not it's");

_.templateSettings = {
start : '{{',
end : '}}',
interpolate : /\{\{(.+?)\}\}/g
};

var mustache = _.template("Hello {{planet}}!");
equals(mustache({planet : "World"}), "Hello World!", "can mimic mustache.js");
});

});
9 changes: 5 additions & 4 deletions underscore-min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 14 additions & 13 deletions underscore.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
propertyIsEnumerable = Object.prototype.propertyIsEnumerable;

// Current version.
_.VERSION = '0.5.5';
_.VERSION = '0.5.6';

// ------------------------ Collection Functions: ---------------------------

Expand Down Expand Up @@ -559,28 +559,29 @@
return prefix ? prefix + id : id;
};

// By default, Underscore uses ERB-style template delimiters, change the
// following template settings to use alternative delimiters.
_.templateSettings = {
start : '<%',
end : '%>',
interpolate : /<%=(.+?)%>/g
};

// JavaScript templating a-la ERB, pilfered from John Resig's
// "Secrets of the JavaScript Ninja", page 83.
// Single-quote fix from Rick Strahl's version.
_.template = function(str, data) {
var start = '<%', end = '%>',
interpolate = /<%=(.+?)%>/g;
if(str && !_.isString(str)) {
start = str.start || start;
end = str.end || end;
interpolate = str.interpolate || interpolate;
str = str.template;
}
var c = _.templateSettings;
var fn = new Function('obj',
'var p=[],print=function(){p.push.apply(p,arguments);};' +
'with(obj){p.push(\'' +
str.replace(/[\r\t\n]/g, " ")
.replace(new RegExp("'(?=[^"+end[0]+"]*"+end+")","g"),"\t")
.replace(new RegExp("'(?=[^"+c.end[0]+"]*"+c.end+")","g"),"\t")
.split("'").join("\\'")
.split("\t").join("'")
.replace(interpolate, "',$1,'")
.split(start).join("');")
.split(end).join("p.push('")
.replace(c.interpolate, "',$1,'")
.split(c.start).join("');")
.split(c.end).join("p.push('")
+ "');}return p.join('');");
return data ? fn(data) : fn;
};
Expand Down

0 comments on commit 7d9e603

Please sign in to comment.