├── templatec ├── template-0.3-1.rockspec ├── tests.lua ├── LICENSE.txt ├── README.md └── template.lua /templatec: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env lua 2 | local template = require "template" 3 | local i = 1 4 | local minify = false 5 | while i <= #arg do 6 | if arg[i] == "-o" then 7 | i = i + 1 8 | io.output(arg[i]) 9 | elseif arg[i] == "-m" then 10 | minify = true 11 | else 12 | io.input(arg[i]) 13 | end 14 | i = i + 1 15 | end 16 | io.write(template.parse(io.read("*a"), minify)) 17 | -------------------------------------------------------------------------------- /template-0.3-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "template" 2 | version = "0.3-1" 3 | 4 | source = { 5 | url = "git://github.com/dannote/lua-template.git" 6 | } 7 | 8 | description = { 9 | summary = "The simplest Lua template engine in just a few lines of code", 10 | homepage = "https://github.com/dannote/lua-template", 11 | maintainer = "Danila Poyarkov ", 12 | license = "MIT" 13 | } 14 | 15 | dependencies = { 16 | "lua >= 5.0" 17 | } 18 | 19 | build = { 20 | type = "builtin", 21 | modules = { 22 | ["template"] = "template.lua" 23 | }, 24 | install = { 25 | bin = {"templatec"} 26 | } 27 | } -------------------------------------------------------------------------------- /tests.lua: -------------------------------------------------------------------------------- 1 | require 'busted.runner'() 2 | 3 | describe("template module", function() 4 | local template = require('template') 5 | 6 | describe("template processing", function() 7 | it("processes simple template", function() 8 | local func = template.compile("Hello, <%= name %>!") 9 | local output = {} 10 | template.print(func, { name = "World" }, function(s) table.insert(output, s) end) 11 | assert.equal("Hello, World!", table.concat(output, "")) 12 | end) 13 | 14 | it("processes conditional template", function() 15 | local func = template.compile("Hello, <%= name %>!Guest") 16 | local output = {} 17 | template.print(func, { name = "World" }, function(s) table.insert(output, s) end) 18 | assert.equal("Hello, World!", table.concat(output, "")) 19 | end) 20 | 21 | it("errors on invalid template", function() 22 | assert.has_error(function() 23 | template.compile("<%= ) %>") 24 | end) 25 | end) 26 | end) 27 | end) 28 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Danila Poyarkov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | lua-template 2 | ============ 3 | 4 | The simplest Lua HTML template engine in just a few lines of code 5 | 6 | Installation 7 | ------------ 8 | 9 | `luarocks install template` 10 | 11 | Compiling templates 12 | ------------------- 13 | Templates can be compiled by either running 14 | 15 | `templatec template.tpl -o template.lua` 16 | 17 | nor by passing a string to `template.compile`. 18 | 19 | Syntax 20 | ------ 21 | In short, Lua expressions must be included between percent signs and Lua statements must be placed beetween question marks. 22 | 23 | ### Variables and expressions 24 | ```html 25 | <% next %> 26 | ``` 27 | 28 | ### Variables and expressions without HTML escaping 29 | ```html 30 | <%= content %> 31 | ``` 32 | 33 | ### Loops 34 | ```html 35 | 40 | ``` 41 | 42 | ### Conditional 43 | ```html 44 | 2 then ?> 45 | Impossible! 46 | 47 | That's right! 48 | 49 | ``` 50 | 51 | ### Template inclusion 52 | Templates are compiled to a general Lua file and hence can be loaded by `require` statement: 53 | ```html 54 | 55 | 56 | 57 | 58 | ``` 59 | 60 | Evaluating templates 61 | -------------------- 62 | `template.print` takes three arguments: template function, a table with variables passed to the template and optionally a callback function, which handles string printing (`print` is used by default). 63 | 64 | Compressing templates 65 | --------------------- 66 | `template.compile` has an optional `minify` argument and `templatec` has `-m` option. 67 | -------------------------------------------------------------------------------- /template.lua: -------------------------------------------------------------------------------- 1 | local template = {} 2 | 3 | function template.escape(data) 4 | return tostring(data or ''):gsub("[\">/<'&]", { 5 | ["&"] = "&", 6 | ["<"] = "<", 7 | [">"] = ">", 8 | ['"'] = """, 9 | ["'"] = "'", 10 | ["/"] = "/" 11 | }) 12 | end 13 | 14 | function template.print(data, args, callback) 15 | local callback = callback or print 16 | local function exec(data) 17 | if type(data) == "function" then 18 | local env = args or {} 19 | setmetatable(env, { __index = _G }) 20 | if _ENV then -- Lua 5.2+ 21 | local wrapper, err = load([[ 22 | return function(_ENV, exec) 23 | local f = ... 24 | f(exec) 25 | end 26 | ]], "wrapper", "t", env) 27 | if not wrapper then 28 | error(err) 29 | end 30 | wrapper()(env, exec, data) 31 | else 32 | setfenv(data, env) 33 | data(exec) 34 | end 35 | else 36 | callback(tostring(data or '')) 37 | end 38 | end 39 | exec(data) 40 | end 41 | 42 | function template.parse(data, minify) 43 | local str = 44 | "return function(_)" .. 45 | "function __(...)" .. 46 | "_(require('template').escape(...))" .. 47 | "end " .. 48 | "_[=[" .. 49 | data: 50 | gsub("[][]=[][]", ']=]_"%1"_[=['): 51 | gsub("<%%=", "]=]_("): 52 | gsub("<%%", "]=]__("): 53 | gsub("%%>", ")_[=["): 54 | gsub("<%?", "]=] "): 55 | gsub("%?>", " _[=[") .. 56 | "]=] " .. 57 | "end" 58 | if minify then 59 | str = str: 60 | gsub("^[ %s]*", ""): 61 | gsub("[ %s]*$", ""): 62 | gsub("%s+", " ") 63 | end 64 | return str 65 | end 66 | 67 | function template.compile(...) 68 | local f, err = loadstring(template.parse(...)) 69 | if err then 70 | error(err) 71 | end 72 | return f() 73 | end 74 | 75 | return template 76 | --------------------------------------------------------------------------------