forked from torhve/Amatyr
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtir.lua
127 lines (103 loc) · 3.26 KB
/
tir.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
--
-- tortir (C) Tor Hveem
-- Simple template based on Tir (C) Zed Shaw
--
-- License: BSD 3-clause : http://tir.mongrel2.org/wiki/license.html
--
--
local require = require
local setmetatable = setmetatable
local io = require "io"
local assert = assert
local string = string
local table = table
local loadstring = loadstring
local load = load
local setfenv = setfenv
local getfenv = getfenv
module('tir', package.seeall)
-- Simplistic HTML escaping.
function escape(s)
if s == nil then return '' end
local esc, i = s:gsub('&', '&'):gsub('<', '<'):gsub('>', '>')
return esc
end
-- Simplistic Tir template escaping, for when you need to show lua code on web.
local function tirescape(s)
if s == nil then return '' end
local esc, i = s:gsub('{', '{'):gsub('}', '}')
return tir.escape(esc)
end
-- Helper function that loads a file into ram.
function load_file(name)
local intmp = assert(io.open(name, 'r'))
local content = intmp:read('*a')
intmp:close()
return content
end
-- Used in template parsing to figure out what each {} does.
local VIEW_ACTIONS = {
['{%'] = function(code)
return code
end,
['{{'] = function(code)
return ('_result[#_result+1] = %s'):format(code)
end,
['{('] = function(code)
return ([[
if not _children[%s] then
local tir = require 'template'
_children[%s] = tir.tload(%s)
end
_result[#_result+1] = _children[%s](getfenv())
]]):format(code, code, code, code)
end,
['{<'] = function(code)
return ('local tir = require "tir" _result[#_result+1] = tir.escape(%s)'):format(code)
end,
}
-- Takes a view template and optional name (usually a file) and
-- returns a function you can call with a table to render the view.
function compile_view(tmpl, name)
local tmpl = tmpl .. '{}'
local code = {'local _result, _children = {}, {}\n'}
for text, block in string.gmatch(tmpl, "([^{]-)(%b{})") do
local act = VIEW_ACTIONS[block:sub(1,2)]
local output = text
if act then
code[#code+1] = '_result[#_result+1] = [[' .. text .. ']]'
code[#code+1] = act(block:sub(3,-3))
elseif #block > 2 then
code[#code+1] = '_result[#_result+1] = [[' .. text .. block .. ']]'
else
code[#code+1] = '_result[#_result+1] = [[' .. text .. ']]'
end
end
code[#code+1] = 'return table.concat(_result)'
code = table.concat(code, '\n')
-- use load from lua 5.2 or luajit
local func, err = load(code, name, 't', mt )
if err then
assert(func, err)
end
return function(context)
assert(context, "You must always pass in a table for context.")
setmetatable(context, {__index=_G})
setfenv(func, context)
return func()
end
end
-- Return loaded template
function tload(name)
local tempf = load_file(name)
assert(tempf, "Template " .. name .. " does not exist.")
return compile_view(tempf, name)
end
-- Recompile dynamically
function dynload(name)
return function (params)
local tempf = load_file(name)
assert(tempf, "Template " .. name .. " does not exist.")
return compile_view(tempf, name)(params)
end
end