| @@ -2,4 +2,4 @@ var comments = { | |||||
| title: function() { | title: function() { | ||||
| return "A Comedy of Errors"; | return "A Comedy of Errors"; | ||||
| } | } | ||||
| }; | |||||
| }; | |||||
| @@ -1,14 +0,0 @@ | |||||
| $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib' | |||||
| require 'mustache' | |||||
| class Escaped < Mustache | |||||
| self.path = File.dirname(__FILE__) | |||||
| def title | |||||
| "Bear > Shark" | |||||
| end | |||||
| end | |||||
| if $0 == __FILE__ | |||||
| puts Escaped.to_html | |||||
| end | |||||
| @@ -1 +0,0 @@ | |||||
| Again, {{title}}! | |||||
| @@ -1,26 +0,0 @@ | |||||
| $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib' | |||||
| require 'mustache' | |||||
| class Simple < Mustache | |||||
| self.path = File.dirname(__FILE__) | |||||
| def name | |||||
| "Chris" | |||||
| end | |||||
| def value | |||||
| 10_000 | |||||
| end | |||||
| def taxed_value | |||||
| value - (value * 0.4) | |||||
| end | |||||
| def in_ca | |||||
| true | |||||
| end | |||||
| end | |||||
| if $0 == __FILE__ | |||||
| puts Simple.to_html | |||||
| end | |||||
| @@ -0,0 +1,7 @@ | |||||
| var template_partial = { | |||||
| title: function() { | |||||
| return "Welcome"; | |||||
| } | |||||
| } | |||||
| var inner_partial = "Again, {{title}}!"; | |||||
| @@ -1,14 +0,0 @@ | |||||
| $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib' | |||||
| require 'mustache' | |||||
| class TemplatePartial < Mustache | |||||
| self.path = File.dirname(__FILE__) | |||||
| def title | |||||
| "Welcome" | |||||
| end | |||||
| end | |||||
| if $0 == __FILE__ | |||||
| puts TemplatePartial.to_html | |||||
| end | |||||
| @@ -0,0 +1,2 @@ | |||||
| <h1>Welcome</h1> | |||||
| Again, Welcome! | |||||
| @@ -1,14 +0,0 @@ | |||||
| $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib' | |||||
| require 'mustache' | |||||
| class Unescaped < Mustache | |||||
| self.path = File.dirname(__FILE__) | |||||
| def title | |||||
| "Bear > Shark" | |||||
| end | |||||
| end | |||||
| if $0 == __FILE__ | |||||
| puts Unescaped.to_html | |||||
| end | |||||
| @@ -0,0 +1,24 @@ | |||||
| var view_partial = { | |||||
| greeting: function() { | |||||
| return "Welcome"; | |||||
| }, | |||||
| farewell: function() { | |||||
| return "Fair enough, right?"; | |||||
| } | |||||
| }; | |||||
| var simple = { | |||||
| name: "Chris", | |||||
| value: 10000, | |||||
| taxed_value: function() { | |||||
| return this.value - (this.value * 0.4); | |||||
| }, | |||||
| in_ca: true | |||||
| }; | |||||
| var simple_template = "Hello {{name}}\n" + | |||||
| "You have just won ${{value}}!\n" + | |||||
| "{{#in_ca}}\n" + | |||||
| "Well, ${{ taxed_value }}, after taxes.\n" + | |||||
| "{{/in_ca}}\n"; | |||||
| @@ -1,18 +0,0 @@ | |||||
| $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib' | |||||
| require 'mustache' | |||||
| class ViewPartial < Mustache | |||||
| self.path = File.dirname(__FILE__) | |||||
| def greeting | |||||
| "Welcome" | |||||
| end | |||||
| def farewell | |||||
| "Fair enough, right?" | |||||
| end | |||||
| end | |||||
| if $0 == __FILE__ | |||||
| puts ViewPartial.to_html | |||||
| end | |||||
| @@ -0,0 +1,6 @@ | |||||
| <h1>Welcome</h1> | |||||
| Hello Chris | |||||
| You have just won $10000! | |||||
| Well, $6000, after taxes. | |||||
| <h3>Fair enough, right?</h3> | |||||
| @@ -3,7 +3,7 @@ | |||||
| by Jan Lehnardt <jan@apache.org> | by Jan Lehnardt <jan@apache.org> | ||||
| Thanks @defunkt for the awesome code | Thanks @defunkt for the awesome code | ||||
| TBD: License | |||||
| TBD: MIT, see LICENSE | |||||
| ChangeLog: | ChangeLog: | ||||
| - 04.10.2009: Ininitial port at http://devhouseberlin.de/ | - 04.10.2009: Ininitial port at http://devhouseberlin.de/ | ||||
| @@ -16,7 +16,7 @@ var Mustache = { | |||||
| debug: true, | debug: true, | ||||
| stack: " ", | stack: " ", | ||||
| context: {}, | context: {}, | ||||
| to_html: function(view, template) { | |||||
| to_html: function(template, view) { | |||||
| return this.render(template, view); | return this.render(template, view); | ||||
| }, | }, | ||||
| @@ -29,10 +29,23 @@ var Mustache = { | |||||
| this.context = context = this.merge((this.context || {}), view); | this.context = context = this.merge((this.context || {}), view); | ||||
| var html = this.render_section(template); | var html = this.render_section(template); | ||||
| // restore context, recursion might have messed it up | // restore context, recursion might have messed it up | ||||
| // this.context = context; | |||||
| this.context = context; | |||||
| return this.render_tags(html); | return this.render_tags(html); | ||||
| }, | }, | ||||
| render_partial: function(name) { | |||||
| var evil_name = eval(name) | |||||
| switch(typeof evil_name) { | |||||
| case "string": | |||||
| return this.to_html(evil_name, ""); | |||||
| case "object": | |||||
| var tpl = name + "_template"; | |||||
| return this.to_html(eval(tpl), evil_name); | |||||
| default: | |||||
| throw("Unknown partial type."); | |||||
| } | |||||
| }, | |||||
| merge: function(a, b) { | merge: function(a, b) { | ||||
| for(var name in b) { | for(var name in b) { | ||||
| if(b.hasOwnProperty(name)) { | if(b.hasOwnProperty(name)) { | ||||
| @@ -47,11 +60,8 @@ var Mustache = { | |||||
| return template; | return template; | ||||
| } | } | ||||
| var that = this; | var that = this; | ||||
| return template.replace(/\{\{\#(.+)\}\}\s*(.+)\s*\{\{\/\1\}\}\s*/mg, | |||||
| return template.replace(/\{\{\#(.+)\}\}\s*([\s\S]+)\{\{\/\1\}\}\s*/mg, | |||||
| function(match, name, content) { | function(match, name, content) { | ||||
| print(match); | |||||
| print(name); | |||||
| print(content); | |||||
| var value = that.find(name); | var value = that.find(name); | ||||
| if(that.is_array(value)) { | if(that.is_array(value)) { | ||||
| return value.map(function(row) { | return value.map(function(row) { | ||||
| @@ -65,10 +75,10 @@ var Mustache = { | |||||
| } | } | ||||
| ); | ); | ||||
| }, | }, | ||||
| is_array: function(a) { | is_array: function(a) { | ||||
| return (a && | |||||
| typeof a === 'object' && | |||||
| return (a && | |||||
| typeof a === 'object' && | |||||
| a.constructor === Array); | a.constructor === Array); | ||||
| }, | }, | ||||
| @@ -77,18 +87,30 @@ var Mustache = { | |||||
| var that = this; | var that = this; | ||||
| return template.replace(/\{\{(!|<|\{)?([^\/#]+?)\1?\}\}+/mg, | return template.replace(/\{\{(!|<|\{)?([^\/#]+?)\1?\}\}+/mg, | ||||
| function (match, operator, name) { | function (match, operator, name) { | ||||
| switch(operator) { | |||||
| case "!": // ignore comments | |||||
| return match; | |||||
| // TODO: partials | |||||
| // case "<": // render partial | |||||
| // return this.render_partial() | |||||
| case '{': // the triple mustache is unescaped | |||||
| return that.find(name); | |||||
| default: // escape the value | |||||
| return that.find(name); | |||||
| switch(operator) { | |||||
| case "!": // ignore comments | |||||
| return match; | |||||
| case "<": // render partial | |||||
| return that.render_partial(name); | |||||
| case '{': // the triple mustache is unescaped | |||||
| return that.find(name); | |||||
| default: // escape the value | |||||
| return that.escape(that.find(name)); | |||||
| } | |||||
| }, this); | |||||
| }, | |||||
| escape: function(s) { | |||||
| return s.toString().replace(/[&"<>\\]/g, function(s) { | |||||
| switch(s) { | |||||
| case "&": return "&"; | |||||
| case "\\": return "\\\\";; | |||||
| case '"': return '\"';; | |||||
| case "<": return "<"; | |||||
| case ">": return ">"; | |||||
| default: return s; | |||||
| } | } | ||||
| }, this); | |||||
| }); | |||||
| }, | }, | ||||
| find: function(name) { | find: function(name) { | ||||
| @@ -3,7 +3,7 @@ | |||||
| by Jan Lehnardt <jan@apache.org> | by Jan Lehnardt <jan@apache.org> | ||||
| Thanks @defunkt for the awesome code | Thanks @defunkt for the awesome code | ||||
| TBD: License | |||||
| TBD: MIT, see LICENSE | |||||
| ChangeLog: | ChangeLog: | ||||
| - 04.10.2009: Ininitial port at http://devhouseberlin.de/ | - 04.10.2009: Ininitial port at http://devhouseberlin.de/ | ||||
| @@ -16,7 +16,7 @@ var Mustache = { | |||||
| debug: true, | debug: true, | ||||
| stack: " ", | stack: " ", | ||||
| context: {}, | context: {}, | ||||
| to_html: function(view, template) { | |||||
| to_html: function(template, view) { | |||||
| return this.render(template, view); | return this.render(template, view); | ||||
| }, | }, | ||||
| @@ -29,10 +29,23 @@ var Mustache = { | |||||
| this.context = context = this.merge((this.context || {}), view); | this.context = context = this.merge((this.context || {}), view); | ||||
| var html = this.render_section(template); | var html = this.render_section(template); | ||||
| // restore context, recursion might have messed it up | // restore context, recursion might have messed it up | ||||
| // this.context = context; | |||||
| this.context = context; | |||||
| return this.render_tags(html); | return this.render_tags(html); | ||||
| }, | }, | ||||
| render_partial: function(name) { | |||||
| var evil_name = eval(name) | |||||
| switch(typeof evil_name) { | |||||
| case "string": | |||||
| return this.to_html(evil_name, ""); | |||||
| case "object": | |||||
| var tpl = name + "_template"; | |||||
| return this.to_html(eval(tpl), evil_name); | |||||
| default: | |||||
| throw("Unknown partial type."); | |||||
| } | |||||
| }, | |||||
| merge: function(a, b) { | merge: function(a, b) { | ||||
| for(var name in b) { | for(var name in b) { | ||||
| if(b.hasOwnProperty(name)) { | if(b.hasOwnProperty(name)) { | ||||
| @@ -47,11 +60,8 @@ var Mustache = { | |||||
| return template; | return template; | ||||
| } | } | ||||
| var that = this; | var that = this; | ||||
| return template.replace(/\{\{\#(.+)\}\}\s*(.+)\s*\{\{\/\1\}\}\s*/mg, | |||||
| return template.replace(/\{\{\#(.+)\}\}\s*([\s\S]+)\{\{\/\1\}\}\s*/mg, | |||||
| function(match, name, content) { | function(match, name, content) { | ||||
| print(match); | |||||
| print(name); | |||||
| print(content); | |||||
| var value = that.find(name); | var value = that.find(name); | ||||
| if(that.is_array(value)) { | if(that.is_array(value)) { | ||||
| return value.map(function(row) { | return value.map(function(row) { | ||||
| @@ -65,10 +75,10 @@ var Mustache = { | |||||
| } | } | ||||
| ); | ); | ||||
| }, | }, | ||||
| is_array: function(a) { | is_array: function(a) { | ||||
| return (a && | |||||
| typeof a === 'object' && | |||||
| return (a && | |||||
| typeof a === 'object' && | |||||
| a.constructor === Array); | a.constructor === Array); | ||||
| }, | }, | ||||
| @@ -77,18 +87,30 @@ var Mustache = { | |||||
| var that = this; | var that = this; | ||||
| return template.replace(/\{\{(!|<|\{)?([^\/#]+?)\1?\}\}+/mg, | return template.replace(/\{\{(!|<|\{)?([^\/#]+?)\1?\}\}+/mg, | ||||
| function (match, operator, name) { | function (match, operator, name) { | ||||
| switch(operator) { | |||||
| case "!": // ignore comments | |||||
| return match; | |||||
| // TODO: partials | |||||
| // case "<": // render partial | |||||
| // return this.render_partial() | |||||
| case '{': // the triple mustache is unescaped | |||||
| return that.find(name); | |||||
| default: // escape the value | |||||
| return that.find(name); | |||||
| switch(operator) { | |||||
| case "!": // ignore comments | |||||
| return match; | |||||
| case "<": // render partial | |||||
| return that.render_partial(name); | |||||
| case '{': // the triple mustache is unescaped | |||||
| return that.find(name); | |||||
| default: // escape the value | |||||
| return that.escape(that.find(name)); | |||||
| } | |||||
| }, this); | |||||
| }, | |||||
| escape: function(s) { | |||||
| return s.toString().replace(/[&"<>\\]/g, function(s) { | |||||
| switch(s) { | |||||
| case "&": return "&"; | |||||
| case "\\": return "\\\\";; | |||||
| case '"': return '\"';; | |||||
| case "<": return "<"; | |||||
| case ">": return ">"; | |||||
| default: return s; | |||||
| } | } | ||||
| }, this); | |||||
| }); | |||||
| }, | }, | ||||
| find: function(name) { | find: function(name) { | ||||
| @@ -109,32 +131,31 @@ var Mustache = { | |||||
| }, | }, | ||||
| }; | }; | ||||
| var complex = { | |||||
| header: function() { | |||||
| return "Colors"; | |||||
| var view_partial = { | |||||
| greeting: function() { | |||||
| return "Welcome"; | |||||
| }, | }, | ||||
| item: [ | |||||
| {name: "red", current: true, url: "#Red"}, | |||||
| {name: "green", current: false, url: "#Green"}, | |||||
| {name: "blue", current: false, url: "#Blue"} | |||||
| ], | |||||
| link: function() { | |||||
| var v = this["current"] === true; | |||||
| // print("link() returns " + v); | |||||
| return v; | |||||
| }, | |||||
| list: function() { | |||||
| var v = this.item.length !== 0; | |||||
| // print("list() returns " + v); | |||||
| return v; | |||||
| }, | |||||
| empty: function() { | |||||
| var v = this.item.length === 0; | |||||
| // print("empty() returns " + v); | |||||
| return v; | |||||
| farewell: function() { | |||||
| return "Fair enough, right?"; | |||||
| } | } | ||||
| }; | }; | ||||
| var template = "<h1>{{header}}<\/h1>\n{{#list}}\n <ul>\n {{#item}}\n {{#current}}\n <li><strong>{{name}}<\/strong><\/li>\n {{\/current}}\n {{#link}}\n <li><a href=\"{{url}}\">{{name}}<\/a><\/li>\n {{\/link}}\n {{\/item}}\n <\/ul>\n{{\/list}}\n{{#empty}}\n <p>The list is empty.<\/p>\n{{\/empty}}"; | |||||
| var result = Mustache.to_html(complex, template); | |||||
| var simple = { | |||||
| name: "Chris", | |||||
| value: 10000, | |||||
| taxed_value: function() { | |||||
| return this.value - (this.value * 0.4); | |||||
| }, | |||||
| in_ca: true | |||||
| }; | |||||
| var simple_template = "Hello {{name}}\n" + | |||||
| "You have just won ${{value}}!\n" + | |||||
| "{{#in_ca}}\n" + | |||||
| "Well, ${{ taxed_value }}, after taxes.\n" + | |||||
| "{{/in_ca}}\n"; | |||||
| var template = "<h1>{{greeting}}<\/h1>\n{{<simple}}\n<h3>{{farewell}}<\/h3>"; | |||||
| var result = Mustache.to_html(template, view_partial); | |||||
| print(result); | print(result); | ||||
| @@ -0,0 +1,14 @@ | |||||
| var a = function(s) { | |||||
| return s.replace(/[&"\<>]/g, function(s) { | |||||
| switch(s) { | |||||
| case "&": return "&"; break; | |||||
| case "\\": return "\\\\"; break; | |||||
| case '"': return '\"'; break; | |||||
| case "<": return "<"; break; | |||||
| case ">": return ">"; break; | |||||
| default: return String(s); break; | |||||
| } | |||||
| }); | |||||
| }; | |||||
| print(a("as&<")); | |||||
| @@ -15,7 +15,7 @@ runner = <<-JS | |||||
| #{mustache} | #{mustache} | ||||
| #{view} | #{view} | ||||
| var template = #{template}; | var template = #{template}; | ||||
| var result = Mustache.to_html(#{testname}, template); | |||||
| var result = Mustache.to_html(template, #{testname}); | |||||
| print(result); | print(result); | ||||
| JS | JS | ||||
| @@ -24,11 +24,11 @@ File.open("runner.js", 'w') {|f| f << runner} | |||||
| result = `js runner.js` | result = `js runner.js` | ||||
| if(result == expect) | if(result == expect) | ||||
| puts "." | |||||
| puts "OK" | |||||
| else | else | ||||
| puts "Error in #{testname}" | puts "Error in #{testname}" | ||||
| puts "Expected" | puts "Expected" | ||||
| puts expect | |||||
| puts "'#{expect}'" | |||||
| puts "Actual" | puts "Actual" | ||||
| puts result | |||||
| puts "'#{result}'" | |||||
| end | end | ||||