From fbd682d9ec4b9e4bf836de5a055e0913d0e8cb1b Mon Sep 17 00:00:00 2001 From: Jeremy Ashkenas Date: Mon, 27 Sep 2010 17:35:43 -0400 Subject: [PATCH] Fixing Issue #35. newlines in evaluated code. --- index.html | 8 +++----- test/utility.js | 12 +++++------- underscore.js | 28 ++++++++++++++-------------- 3 files changed, 22 insertions(+), 26 deletions(-) diff --git a/index.html b/index.html index c8ad84562..8a822781d 100644 --- a/index.html +++ b/index.html @@ -1065,17 +1065,15 @@ _.template(list, {people : ['moe', 'curly', 'larry']});

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 start and end tokens, and an interpolate regex - to match expressions that should be evaluated and inserted. For example, - to perform + Define and an interpolate regex, and an (optional) evaluate regex + to match expressions that should be inserted and evaluated, respectively. + For example, to perform Mustache.js style templating:

 _.templateSettings = {
-  start       : '{{',
-  end         : '}}',
   interpolate : /\{\{(.+?)\}\}/g
 };
 
diff --git a/test/utility.js b/test/utility.js
index a38eb1a98..8619440cc 100644
--- a/test/utility.js
+++ b/test/utility.js
@@ -55,7 +55,9 @@ $(document).ready(function() {
     var result = basicTemplate({thing : 'This'});
     equals(result, "This is gettin' on my noives!", 'can do basic attribute interpolation');
 
-    var fancyTemplate = _.template("");
+    var fancyTemplate = _.template("");
     result = fancyTemplate({people : {moe : "Moe", larry : "Larry", curly : "Curly"}});
     equals(result, "", 'can run arbitrary javascript in templates');
 
@@ -84,8 +86,7 @@ $(document).ready(function() {
     equals(withNewlinesAndTabs({x: 'that'}), 'This\n\t\tis: that.\n\tok.\nend.');
 
     _.templateSettings = {
-      start       : '{{',
-      end         : '}}',
+      evaluate    : /\{\{(.+?)\}\}/g,
       interpolate : /\{\{=(.+?)\}\}/g
     };
 
@@ -100,8 +101,7 @@ $(document).ready(function() {
     equals(quoteInStatementAndBody({foo: "bar"}), "Statement quotes and 'quotes'.");
 
     _.templateSettings = {
-      start       : '',
+      evaluate    : /<\?(.+?)\?>/g,
       interpolate : /<\?=(.+?)\?>/g
     };
 
@@ -116,8 +116,6 @@ $(document).ready(function() {
     equals(quoteInStatementAndBody({foo: "bar"}), "Statement quotes and 'quotes'.");
 
     _.templateSettings = {
-      start       : '{{',
-      end         : '}}',
       interpolate : /\{\{(.+?)\}\}/g
     };
 
diff --git a/underscore.js b/underscore.js
index 6b77e3469..7fa8ee21b 100644
--- a/underscore.js
+++ b/underscore.js
@@ -617,8 +617,7 @@
   // By default, Underscore uses ERB-style template delimiters, change the
   // following template settings to use alternative delimiters.
   _.templateSettings = {
-    start       : '<%',
-    end         : '%>',
+    evaluate    : /<%(.+?)%>/g,
     interpolate : /<%=(.+?)%>/g
   };
 
@@ -628,21 +627,22 @@
   // With alterations for arbitrary delimiters, and to preserve whitespace.
   _.template = function(str, data) {
     var c  = _.templateSettings;
-    var endMatch = new RegExp("'(?=[^"+c.end.substr(0, 1)+"]*"+escapeRegExp(c.end)+")","g");
-    var fn = new Function('obj',
-      'var __p=[],print=function(){__p.push.apply(__p,arguments);};' +
+    var tmpl = 'var __p=[],print=function(){__p.push.apply(__p,arguments);};' +
       'with(obj||{}){__p.push(\'' +
-      str.replace(/\r/g, '\\r')
+      str.split("'").join("\\'")
+         .replace(c.interpolate, function(match, code) {
+           return "'," + code.replace(/\\'/g, "'") + ",'";
+         })
+         .replace(c.evaluate || null, function(match, code) {
+           return "');" + code.replace(/\\'/g, "'")
+                              .replace(/[\r\n\t]/g, ' ') + "__p.push('";
+         })
+         .replace(/\r/g, '\\r')
          .replace(/\n/g, '\\n')
          .replace(/\t/g, '\\t')
-         .replace(endMatch,"✄")
-         .split("'").join("\\'")
-         .split("✄").join("'")
-         .replace(c.interpolate, "',$1,'")
-         .split(c.start).join("');")
-         .split(c.end).join("__p.push('")
-         + "');}return __p.join('');");
-    return data ? fn(data) : fn;
+         + "');}return __p.join('');";
+    var func = new Function('obj', tmpl);
+    return data ? func(data) : func;
   };
 
   // ------------------------------- Aliases ----------------------------------