pax_global_header 0000666 0000000 0000000 00000000064 11721651077 0014521 g ustar 00root root 0000000 0000000 52 comment=90cc5f0d185282b9bc08e7be7a134606d36ada3f janl-mustache.js-90cc5f0/ 0000775 0000000 0000000 00000000000 11721651077 0015302 5 ustar 00root root 0000000 0000000 janl-mustache.js-90cc5f0/.gitignore 0000664 0000000 0000000 00000000206 11721651077 0017270 0 ustar 00root root 0000000 0000000 # ignore temp vim files *.swp .DS_Store .rvmrc runner.js lib jquery.mustache.js qooxdoo.mustache.js dojox yui3 requirejs.mustache.js janl-mustache.js-90cc5f0/.travis.yml 0000664 0000000 0000000 00000000136 11721651077 0017413 0 ustar 00root root 0000000 0000000 rvm: - 1.9.2 before_script: - sudo apt-get -y install xulrunner-2.0 - gem install rspec janl-mustache.js-90cc5f0/LICENSE 0000664 0000000 0000000 00000002151 11721651077 0016306 0 ustar 00root root 0000000 0000000 The MIT License Copyright (c) 2009 Chris Wanstrath (Ruby) Copyright (c) 2010 Jan Lehnardt (JavaScript) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. janl-mustache.js-90cc5f0/README.md 0000664 0000000 0000000 00000021174 11721651077 0016566 0 ustar 00root root 0000000 0000000 # mustache.js — Logic-less {{mustache}} templates with JavaScript > What could be more logical awesome than no logic at all? [mustache.js](http://github.com/janl/mustache.js) is an implementation of the [Mustache](http://mustache.github.com/) templating system in JavaScript. [Mustache](http://mustache.github.com/) is a logic-less template syntax. It can be used for HTML, config files, source code - anything. It works by expanding tags in a template using values provided in a hash or object. We call it "logic-less" because there are no if statements, else clauses, or for loops. Instead there are only tags. Some tags are replaced with a value, some nothing, and others a series of values. For a language-agnostic overview of Mustache's template syntax, see the `mustache(5)` [manpage](http://mustache.github.com/mustache.5.html). ## Where to use mustache.js? You can use mustache.js to render templates in many various scenarios where you can use JavaScript. For example, you can render templates in a browser, server-side using [node](http://nodejs.org/), in [CouchDB](http://couchdb.apache.org/) views, or in almost any other environment where you can use JavaScript. ## Who uses mustache.js? An updated list of mustache.js users is kept [on the Github wiki](http://wiki.github.com/janl/mustache.js/beard-competition). Add yourself or your company if you use mustache.js! ## Usage Below is quick example how to use mustache.js: var view = { title: "Joe", calc: function() { return 2 + 4; } }; var html = Mustache.to_html("{{title}} spends {{calc}}", view); In this example, the `Mustache.to_html` function takes two parameters: 1) the [mustache](http://mustache.github.com/) template and 2) a `view` object that contains the data and code needed to render the template. ## Template Tag Types There are several types of tags currently implemented in mustache.js. ### Simple Tags Tags are always surrounded by mustaches like this `{{foobar}}`. var view = {name: "Joe", say_hello: function(){ return "hello" }} template = "{{say_hello}}, {{name}}" #### Accessing values in nested objects (Dot Notation) To access data logically grouped into nested objects, specify a '.' delimited path to the value. var contact = { name: {first: "Bill", last: "Bobitybob" }, age: 37 } template = "Hello, {{name.first}} {{name.last}}. You are {{age}} years old." *NOTICE*: The dot notation feature was recently implemented for the 0.4 release, which is not out as of Nov 9 2011. You can find the feature in the current master branch of mustachejs. ### Conditional Sections Conditional sections begin with `{{#condition}}` and end with `{{/condition}}`. When `condition` evaluates to true, the section is rendered, otherwise the whole block will output nothing at all. `condition` may be a function returning true/false or a simple boolean. var view = {condition: function() { // [...your code goes here...] return true; }} {{#condition}} I will be visible if condition is true {{/condition}} ### Enumerable Sections Enumerable Sections use the same syntax as condition sections do. `{{#shopping_items}}` and `{{/shopping_items}}`. Actually the view decides how mustache.js renders the section. If the view returns an array, it will iterator over the items. Use `{{.}}` to access the current item inside the enumeration section. var view = {name: "Joe's shopping card", items: ["bananas", "apples"]} var template = "{{name}}:
{{street}}
{{city}}, {{state}} {{zip}}
{{/address}} We'll get this output:801 Streetly street
Boston, MA 02101
### Inverted Sections An inverted section opens with `{{^section}}` instead of `{{#section}}` and uses a boolean negative to evaluate. Empty arrays are considered falsy. View: var inverted_section = { "repo": [] } Template: {{#repo}}{{name}}{{/repo}} {{^repo}}No repos :({{/repo}} Result: No repos :( ### View Partials mustache.js supports a quite powerful but yet simple view partial mechanism. Use the following syntax for partials: `{{>partial_name}}` var view = { name: "Joe", winnings: { value: 1000, taxed_value: function() { return this.value - (this.value * 0.4); } } }; var template = "Welcome, {{name}}! {{>winnings}}" var partials = { winnings: "You just won ${{value}} (which is ${{taxed_value}} after tax)"}; var output = Mustache.to_html(template, view, partials) output will be: Welcome, Joe! You just won $1000 (which is $600 after tax) You invoke a partial with `{{>winnings}}`. Invoking the partial `winnings` will tell mustache.js to look for a object in the context's property `winnings`. It will then use that object as the context for the template found in `partials` for `winnings`. ## Escaping mustache.js does escape all values when using the standard double mustache syntax. Characters which will be escaped: `& \ " ' < >`. To disable escaping, simply use triple mustaches like `{{{unescaped_variable}}}`. Example: Using `{{variable}}` inside a template for `5 > 2` will result in `5 > 2`, where as the usage of `{{{variable}}}` will result in `5 > 2`. ## Streaming To stream template results out of mustache.js, you can pass an optional `send()` callback to the `to_html()` call: Mustache.to_html(template, view, partials, function(line) { print(line); }); ## Pragmas Pragma tags let you alter the behaviour of mustache.js. They have the format of {{%PRAGMANAME}} and they accept options: {{%PRAGMANAME option=value}} ### IMPLICIT-ITERATOR When using a block to iterate over an enumerable (Array), mustache.js expects an objects as enumerable items. The implicit iterator pragma enables optional behaviour of allowing literals as enumerable items. Consider this view: var view = { foo: [1, 2, 3, 4, 5, "french"] }; The following template can iterate over the member `foo`: {{%IMPLICIT-ITERATOR}} {{#foo}} {{.}} {{/foo}} If you don't like the dot in there, the pragma accepts an option to set your own iteration marker: {{%IMPLICIT-ITERATOR iterator=bob}} {{#foo}} {{bob}} {{/foo}} ## Plugins for JavaScript Libraries mustache.js may be built specifically for several different client libraries and platforms, including the following: - [node](http://nodejs.org/) (or other CommonJS platforms) - [jQuery](http://jquery.com/) - [Dojo](http://www.dojotoolkit.org/) - [YUI](http://developer.yahoo.com/yui/) - [RequireJS](http://requirejs.org/) - [qooxdoo](http://qooxdoo.org/) These may be built using [Rake](http://rake.rubyforge.org/) and one of the following commands: $ rake commonjs $ rake jquery $ rake dojo $ rake yui $ rake requirejs $ rake qooxdoo ## Thanks Mustache.js wouldn't kick ass if it weren't for these fine souls: * Chris Wanstrath / defunkt * Alexander Lang / langalex * Sebastian Cohnen / tisba * J Chris Anderson / jchris * Tom Robinson / tlrobinson * Aaron Quint / quirkey * Douglas Crockford * Nikita Vasilyev / NV * Elise Wood / glytch * Damien Mathieu / dmathieu * Jakub Kuźma / qoobaa * Will Leinweber / will * dpree * Jason Smith / jhs * Aaron Gibralter / agibralter * Ross Boucher / boucher * Matt Sanford / mzsanford * Ben Cherry / bcherry * Michael Jackson / mjijackson janl-mustache.js-90cc5f0/Rakefile 0000664 0000000 0000000 00000003444 11721651077 0016754 0 ustar 00root root 0000000 0000000 require 'rake' require 'rake/clean' task :default => :spec desc "Run all specs" task :spec do require 'rspec/core/rake_task' RSpec::Core::RakeTask.new(:spec) do |t| #t.spec_opts = ['--options', "\"#{File.dirname(__FILE__)}/spec/spec.opts\""] t.pattern = 'spec/*_spec.rb' end end def version File.read("mustache.js").match('version: "([^\"]+)",$')[1] end # Creates a rule that uses the .tmpl.{pre,post} stuff to make a final, # wrapped, output file. There is some extra complexity because Dojo and YUI3 # use different template files and final locations. def templated_build(name, opts={}) short = name.downcase source = File.join("wrappers", short) dependencies = ["mustache.js"] + Dir.glob("#{source}/*.tpl.*") target_js = opts[:location] ? "mustache.js" : "#{short}.mustache.js" CLEAN.include(opts[:location] ? opts[:location] : target_js) desc "Package for #{name}" task short.to_sym => dependencies do puts "Packaging for #{name}" mkdir_p opts[:location] if opts[:location] sh "cat #{source}/#{target_js}.tpl.pre mustache.js \ #{source}/#{target_js}.tpl.post > #{opts[:location] || '.'}/#{target_js}" # extra if opts[:extra] sh "sed -e 's/{{version}}/#{version}/' #{source}/#{opts[:extra]} \ > #{opts[:location]}/#{opts[:extra]}" end puts "Done, see #{opts[:location] || '.'}/#{target_js}" end end templated_build "CommonJS", :location => "lib", :extra => "package.json" templated_build "jQuery" templated_build "Dojo", :location => "dojox/string" templated_build "YUI3", :location => "yui3/mustache" templated_build "RequireJS" templated_build "qooxdoo" task :minify do # npm install uglify-js mmjs = "mustache.min.js" `echo "/*! Version: 0.4.2 */" > #{mmjs}` `uglifyjs mustache.js >> #{mmjs}` puts "Created #{mmjs}" end janl-mustache.js-90cc5f0/TESTING.md 0000664 0000000 0000000 00000004337 11721651077 0016750 0 ustar 00root root 0000000 0000000 ## Running the mustache.js Test Suite Notice: the tests are only expected to run on unixoid systems. The mustache.js test suite uses the [RSpec](http://rspec.info/) testing framework. In order to run the tests you'll need to install [Ruby](http://ruby-lang.org/) as well as the `rake`, `rspec` (>=2), and `json` [RubyGems](http://rubygems.org/). ### How to install Ruby and the required gems from source Make sure you have the required tools to compile it: $ apt-get install build-essential libssl-dev libreadline5-dev zlib1g-dev Download and extract the Ruby source, and install it: $ wget ftp://ftp.ruby-lang.org/pub/ruby/stable-snapshot.tar.gz $ tar xvzf stable-snapshot.tar.gz $ cd ruby $ ./configure && make && make install Download and extract RubyGems, and install it: $ wget http://production.cf.rubygems.org/rubygems/rubygems-1.8.12.tgz $ tar xzvf rubygems-1.8.12.tgz $ cd rubygems-1.8.12 $ ruby setup.rb If you want to update RubyGems: $ gem update --system Install the required gems: $ gem install rake rspec json That's it! ### How to install node.js from source $ git clone https://github.com/joyent/node.git $ cd node $ # select the version to install, master is unstable; $ # latest stable version is advertised on http://nodejs.org $ git checkout v0.6.11 $ ./configure $ make $ sudo make install ### How to run the tests The mustache.js test suite currently uses 4 different JavaScript runtime engines to maximize portability across platforms and browsers. They are: * node * SpiderMonkey (Mozilla, Firefox) * JavaScriptCore (WebKit, Safari) * Rhino (Mozilla, Java) When the test suite runs it will automatically determine which platforms are available on your machine and run on all of them. The suite must run on at least one platform in order to succeed. Once you have at least one JavaScript platform installed, you can run the test suite with the following command: $ rake ### How to create a test All test files live in the spec/_files directory. To create a new test: * Create a template file `somename.mustache` * Create a javascript file with data and functions `somename.js` * Create a file the expected result `somename.txt` janl-mustache.js-90cc5f0/mustache.js 0000664 0000000 0000000 00000030312 11721651077 0017450 0 ustar 00root root 0000000 0000000 /* mustache.js — Logic-less templates in JavaScript See http://mustache.github.com/ for more info. */ var Mustache = function () { var _toString = Object.prototype.toString; Array.isArray = Array.isArray || function (obj) { return _toString.call(obj) == "[object Array]"; } var _trim = String.prototype.trim, trim; if (_trim) { trim = function (text) { return text == null ? "" : _trim.call(text); } } else { var trimLeft, trimRight; // IE doesn't match non-breaking spaces with \s. if ((/\S/).test("\xA0")) { trimLeft = /^[\s\xA0]+/; trimRight = /[\s\xA0]+$/; } else { trimLeft = /^\s+/; trimRight = /\s+$/; } trim = function (text) { return text == null ? "" : text.toString().replace(trimLeft, "").replace(trimRight, ""); } } var escapeMap = { "&": "&", "<": "<", ">": ">", '"': '"', "'": ''' }; function escapeHTML(string) { return String(string).replace(/&(?!#?\w+;)|[<>"']/g, function (s) { return escapeMap[s] || s; }); } var regexCache = {}; var Renderer = function () {}; Renderer.prototype = { otag: "{{", ctag: "}}", pragmas: {}, buffer: [], pragmas_implemented: { "IMPLICIT-ITERATOR": true }, context: {}, render: function (template, context, partials, in_recursion) { // reset buffer & set context if (!in_recursion) { this.context = context; this.buffer = []; // TODO: make this non-lazy } // fail fast if (!this.includes("", template)) { if (in_recursion) { return template; } else { this.send(template); return; } } // get the pragmas together template = this.render_pragmas(template); // render the template var html = this.render_section(template, context, partials); // render_section did not find any sections, we still need to render the tags if (html === false) { html = this.render_tags(template, context, partials, in_recursion); } if (in_recursion) { return html; } else { this.sendLines(html); } }, /* Sends parsed lines */ send: function (line) { if (line !== "") { this.buffer.push(line); } }, sendLines: function (text) { if (text) { var lines = text.split("\n"); for (var i = 0; i < lines.length; i++) { this.send(lines[i]); } } }, /* Looks for %PRAGMAS */ render_pragmas: function (template) { // no pragmas if (!this.includes("%", template)) { return template; } var that = this; var regex = this.getCachedRegex("render_pragmas", function (otag, ctag) { return new RegExp(otag + "%([\\w-]+) ?([\\w]+=[\\w]+)?" + ctag, "g"); }); return template.replace(regex, function (match, pragma, options) { if (!that.pragmas_implemented[pragma]) { throw({message: "This implementation of mustache doesn't understand the '" + pragma + "' pragma"}); } that.pragmas[pragma] = {}; if (options) { var opts = options.split("="); that.pragmas[pragma][opts[0]] = opts[1]; } return ""; // ignore unknown pragmas silently }); }, /* Tries to find a partial in the curent scope and render it */ render_partial: function (name, context, partials) { name = trim(name); if (!partials || partials[name] === undefined) { throw({message: "unknown_partial '" + name + "'"}); } if (!context || typeof context[name] != "object") { return this.render(partials[name], context, partials, true); } return this.render(partials[name], context[name], partials, true); }, /* Renders inverted (^) and normal (#) sections */ render_section: function (template, context, partials) { if (!this.includes("#", template) && !this.includes("^", template)) { // did not render anything, there were no sections return false; } var that = this; var regex = this.getCachedRegex("render_section", function (otag, ctag) { // This regex matches _the first_ section ({{#foo}}{{/foo}}), and captures the remainder return new RegExp( "^([\\s\\S]*?)" + // all the crap at the beginning that is not {{*}} ($1) otag + // {{ "(\\^|\\#)\\s*(.+?)\\s*" +// #foo (# == $2, foo == $3), not greedy ctag + // }} "\n*([\\s\\S]*?)" + // between the tag ($2). leading newlines are dropped otag + // {{ "\\/\\s*\\3\\s*" + // /foo (backreference to the opening tag). ctag + // }} "\\s*([\\s\\S]*)$", // everything else in the string ($4). leading whitespace is dropped. "g"); }); // for each {{#foo}}{{/foo}} section do... return template.replace(regex, function (match, before, type, name, content, after) { // before contains only tags, no sections var renderedBefore = before ? that.render_tags(before, context, partials, true) : "", // after may contain both sections and tags, so use full rendering function renderedAfter = after ? that.render(after, context, partials, true) : "", // will be computed below renderedContent, value = that.find(name, context); if (type === "^") { // inverted section if (!value || Array.isArray(value) && value.length === 0) { // false or empty list, render it renderedContent = that.render(content, context, partials, true); } else { renderedContent = ""; } } else if (type === "#") { // normal section if (Array.isArray(value)) { // Enumerable, Let's loop! renderedContent = that.map(value, function (row) { return that.render(content, that.create_context(row), partials, true); }).join(""); } else if (that.is_object(value)) { // Object, Use it as subcontext! renderedContent = that.render(content, that.create_context(value), partials, true); } else if (typeof value == "function") { // higher order section renderedContent = value.call(context, content, function (text) { return that.render(text, context, partials, true); }); } else if (value) { // boolean section renderedContent = that.render(content, context, partials, true); } else { renderedContent = ""; } } return renderedBefore + renderedContent + renderedAfter; }); }, /* Replace {{foo}} and friends with values from our view */ render_tags: function (template, context, partials, in_recursion) { // tit for tat var that = this; var new_regex = function () { return that.getCachedRegex("render_tags", function (otag, ctag) { return new RegExp(otag + "(=|!|>|&|\\{|%)?([^#\\^]+?)\\1?" + ctag + "+", "g"); }); }; var regex = new_regex(); var tag_replace_callback = function (match, operator, name) { switch(operator) { case "!": // ignore comments return ""; case "=": // set new delimiters, rebuild the replace regexp that.set_delimiters(name); regex = new_regex(); return ""; case ">": // render partial return that.render_partial(name, context, partials); case "{": // the triple mustache is unescaped case "&": // & operator is an alternative unescape method return that.find(name, context); default: // escape the value return escapeHTML(that.find(name, context)); } }; var lines = template.split("\n"); for(var i = 0; i < lines.length; i++) { lines[i] = lines[i].replace(regex, tag_replace_callback, this); if (!in_recursion) { this.send(lines[i]); } } if (in_recursion) { return lines.join("\n"); } }, set_delimiters: function (delimiters) { var dels = delimiters.split(" "); this.otag = this.escape_regex(dels[0]); this.ctag = this.escape_regex(dels[1]); }, escape_regex: function (text) { // thank you Simon Willison if (!arguments.callee.sRE) { var specials = [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\' ]; arguments.callee.sRE = new RegExp( '(\\' + specials.join('|\\') + ')', 'g' ); } return text.replace(arguments.callee.sRE, '\\$1'); }, /* find `name` in current `context`. That is find me a value from the view object */ find: function (name, context) { name = trim(name); // Checks whether a value is thruthy or false or 0 function is_kinda_truthy(bool) { return bool === false || bool === 0 || bool; } var value; // check for dot notation eg. foo.bar if (name.match(/([a-z_]+)\./ig)) { var childValue = this.walk_context(name, context); if (is_kinda_truthy(childValue)) { value = childValue; } } else { if (is_kinda_truthy(context[name])) { value = context[name]; } else if (is_kinda_truthy(this.context[name])) { value = this.context[name]; } } if (typeof value == "function") { return value.apply(context); } if (value !== undefined) { return value; } // silently ignore unkown variables return ""; }, walk_context: function (name, context) { var path = name.split('.'); // if the var doesn't exist in current context, check the top level context var value_context = (context[path[0]] != undefined) ? context : this.context; var value = value_context[path.shift()]; while (value != undefined && path.length > 0) { value_context = value; value = value[path.shift()]; } // if the value is a function, call it, binding the correct context if (typeof value == "function") { return value.apply(value_context); } return value; }, // Utility methods /* includes tag */ includes: function (needle, haystack) { return haystack.indexOf(this.otag + needle) != -1; }, // by @langalex, support for arrays of strings create_context: function (_context) { if (this.is_object(_context)) { return _context; } else { var iterator = "."; if (this.pragmas["IMPLICIT-ITERATOR"]) { iterator = this.pragmas["IMPLICIT-ITERATOR"].iterator; } var ctx = {}; ctx[iterator] = _context; return ctx; } }, is_object: function (a) { return a && typeof a == "object"; }, /* Why, why, why? Because IE. Cry, cry cry. */ map: function (array, fn) { if (typeof array.map == "function") { return array.map(fn); } else { var r = []; var l = array.length; for(var i = 0; i < l; i++) { r.push(fn(array[i])); } return r; } }, getCachedRegex: function (name, generator) { var byOtag = regexCache[this.otag]; if (!byOtag) { byOtag = regexCache[this.otag] = {}; } var byCtag = byOtag[this.ctag]; if (!byCtag) { byCtag = byOtag[this.ctag] = {}; } var regex = byCtag[name]; if (!regex) { regex = byCtag[name] = generator(this.otag, this.ctag); } return regex; } }; return({ name: "mustache.js", version: "0.4.2", /* Turns a template and view into HTML */ to_html: function (template, view, partials, send_fun) { var renderer = new Renderer(); if (send_fun) { renderer.send = send_fun; } renderer.render(template, view || {}, partials); if (!send_fun) { return renderer.buffer.join("\n"); } } }); }(); janl-mustache.js-90cc5f0/mustache.js.nuspec 0000664 0000000 0000000 00000001036 11721651077 0020745 0 ustar 00root root 0000000 0000000