Skip to content

Instantly share code, notes, and snippets.

@chrisevans
Forked from haochi/LICENSE.txt
Created August 6, 2011 07:33
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save chrisevans/1129139 to your computer and use it in GitHub Desktop.
Save chrisevans/1129139 to your computer and use it in GitHub Desktop.
tofu: tiny templating engine

Tofu is a logic-less, tweet-size (minified) JavaScript templating engine similar to mustache.js, except that tofu is true logic-less.

Usage

Tofu takes two parameters: a string as template, and a object as values. Variables inside the template are surrounded by a pair of curly braces.

tofu("{ Ich } am { ein } Berliner", { Ich: "I", ein: "a" }); will return I am a Berliner.

You can access nested object values through the familar dot notation that JavaScript uses, so you can do something like

tofu("Welcome to { place.name }! The current temperature is { place.temperature.magnitude } degrees { place.temperature.unit }.", { 
  place: {
    name: "Hong Kong",
    temperature: {
      magnitude: 20,
      unit : "Celcius"
    }
  }
});

and it will return Welcome to Hong Kong! The current temperature is 20 degrees Celcius.

Gotchas

There aren't really any gotchas, but I will just put it here.

  1. I have made the key names for the values object is very forgiving, so you can write something like tofu("{ *** }", { "***": "Hello, World!"}). It should be able to accept any string (including symbols and non-Latin characters) as long as it doesn't include spaces or the closing curly brace (i.e. }). The reasoning is pretty obvious so I am not going to state it here. You can look at the source code for the exact regular expression. My empirical research shows that you won't have to worry about it 99.9999999% of the time. As a general rule of thumb, pretend like you are accessing a JavaScript object using dot notation and you should be fine.

Why should you use Tofu?

Tofu is fast, tiny, and gets the job done if you don't need the fancy conditional and enumerable sections that mustache offers.

function(
a, // the template string
c // the values
){
return a.replace(/{ *([^} ]+) *}/g, // searches for { variable_name } to replace
function( // the replacer function
b, // no use here. it holds the entire "{ variable_name }" string
a // we will use this instead, it holds "variable_name"
){
b=c; // re-assign the placeholder to values
a.replace(/[^.]+/g,function(a){ // find all the key names
b=b[a] // one by one until it's reduced to the one we are looking for
});
return b // return this value to be replaced
}
)
}
function(a,c){return a.replace(/{ *([^} ]+) *}/g,function(b,a){b=c;a.replace(/[^.]+/g,function(a){b=b[a]});return b})}
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2011 Haochi Chen <http://ihaochi.com>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.
{
"name": "tofu",
"description": "Tofu is a logic-less, tweet-size JavaScript templating engine.",
"keywords": [
"tofu",
"template"
]
}
<!DOCTYPE html5>
<html>
<head>
<link rel="stylesheet" href="http://code.jquery.com/qunit/git/qunit.css" type="text/css" media="screen" />
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script src="http://code.jquery.com/qunit/git/qunit.js"></script>
<script>
var tofu = function(a,c){return a.replace(/{ *([^} ]+) *}/g,function(b,a){b=c;a.replace(/[^.]+/g,function(a){b=b[a]});return b})};
</script>
<script>
$(document).ready(function(){
test("Simple object test", function() {
equals("I am a Berliner", tofu("{Ich} am {ein} Berliner", {Ich: "I", ein: "a"}));
});
module("Nested object values");
test("Simple test", function() {
var expected_message = "Welcome to Hong Kong! The current temperature is 20 degrees Celcius."
, template = "Welcome to { place.name }! The current temperature is { place.temperature.magnitude } degrees { place.temperature.unit }."
, rendered_message = tofu(template, {
place: {
name: "Hong Kong",
temperature: {
magnitude: 20,
unit : "Celcius"
}
}
});
equals(expected_message, rendered_message);
});
test("Multiple occurances", function(){
var expected_message = "A rose is a rose is a rose"
, rendered_message = tofu("A { flower } is a { flower } is a { flower }", { flower: "rose" });
equals(expected_message, rendered_message);
});
module("Fancy key names");
test("Invalid JavaScript variable name", function(){
var expected_message = "Tofu is yummy."
, rendered_message = tofu("{ #@! } is { *** }.", { "#@!": "Tofu", "***": "yummy" });
equals(expected_message, rendered_message);
});
test("Accented Latin characters", function(){
var expected_message = "Tofu is yummy."
, rendered_message = tofu("{ á } is { ǽ }.", { "á": "Tofu", "ǽ": "yummy" });
equals(expected_message, rendered_message);
});
test("Asian characters", function(){
var expected_message = "Hong Kong is part of China."
, rendered_message = tofu("{ 香港 } is part of { 中國 }.", { "香港": "Hong Kong", "中國": "China" });
equals(expected_message, rendered_message);
});
module("Misc.");
test("Make sure the outgoing values are the same as the incoming values", function(){
var expected_message = "What does a cat do? It meows!",
template = "What does a { animal.species.name } do? It { animal.species.action }!",
values = { animal: {
species: {
name: "cat",
action: "meows"
},
some_other_stuff: "should still be here!"
} };
equals(expected_message, tofu(template, values));
equals(template, "What does a { animal.species.name } do? It { animal.species.action }!");
deepEqual(values, { animal: {
species: {
name: "cat",
action: "meows"
},
some_other_stuff: "should still be here!"
} });
});
});
</script>
</head>
<body>
<h1 id="qunit-header">QUnit</h1>
<h2 id="qunit-banner"></h2>
<div id="qunit-testrunner-toolbar"></div>
<h2 id="qunit-userAgent"></h2>
<ol id="qunit-tests"></ol>
<div id="qunit-fixture">test markup, will be hidden</div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment