歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> 80行Lua代碼實現一個滿足基本要求的模版引擎

80行Lua代碼實現一個滿足基本要求的模版引擎

日期:2017/3/1 9:49:39   编辑:Linux編程

80行Lua代碼實現一個滿足基本要求的模版引擎,以下內容僅供學習交流,未經嚴格考慮與測試,切勿用於生產環境。

ltemplate.lua

local insert = table.insert

local remove = table.remove

local concat = table.concat

local format = string.format

local loaded = {}

local partten = "(.-){#([^#].-[^#])#}()"

local content = {}

local cur_content = nil

local function ob_start()

cur_content = {}

insert(content, cur_content)

end

local function ob_get_clean()

local ret = concat(cur_content)

remove(content)

cur_content = content[#content]

return ret

end

local function echo(value)

insert(cur_content, value)

end

local function include(path, params)

local bitcode = loaded[path]

if not bitcode then

local fp = io.open(path, "rb")

local template = fp:read('*a')

fp:close()

local results = {}

local last_endpos = 0

for outside, inside, endpos in template:gmatch(partten) do

insert(results, format("echo(%q)", outside))

insert(results, inside)

last_endpos = endpos

end

insert(results, format("echo(%q)", template:sub(last_endpos)))

results = concat(results, "\n")

bitcode = assert(loadstring(results))

loaded[path] = bitcode

end

local env = {

include = include,

echo = echo,

ob_start = ob_start,

ob_get_clean = ob_get_clean

}

setmetatable(env, {__index = function(tb, k)

return params[k] or _G[k]

end})

setfenv(bitcode, env)

bitcode()

end

for i = 1, 100000 do

ob_start()

include(arg[1], {

params = {

a = '1234',

b = '4321'

}

})

ob_get_clean()

end

master.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html lang='zh-CN' xml:lang='zh-CN' xmlns='http://www.w3.org/1999/xhtml'>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>

<meta http-equiv="Content-Language" content="zh-CN"/>

<meta name="robots" content="index, follow" />

<link rel="shortcut icon" type="image/x-icon" href="/img/favicon.ico" />

<title> child&apos;s personal page - 開源中國社區</title>

<link rel="stylesheet/less" href="http://my.oschina.net/lostchild/styles.less?ver=20131219&date=20131110185237" type="text/css" media="screen" />

<link rel="stylesheet" href="/js/2012/poshytip/tip-yellowsimple/tip-yellowsimple.css" type="text/css" />

<link rel="stylesheet" type="text/css" href="/js/2011/fancybox/jquery.fancybox-1.3.4.css" media="screen" />

<script type="text/javascript" src="/js/2012/jquery-1.7.1.min.js"></script>

<script type="text/javascript" src="/js/2012/jquery.form.js"></script>

<script type="text/javascript" src="/js/2011/fancybox/jquery.fancybox-1.3.4.pack.js"></script>

<script type="text/javascript" src="/js/2012/poshytip/jquery.poshytip.min.js"></script>

<script type="text/javascript" src="/js/2011/oschina.js?ver=20121007"></script>

<script type="text/javascript" src="/js/2012/less-1.3.0.min.js"></script>

<script type="text/javascript" src="/js/scrolltopcontrol.js"></script>

<script type='text/javascript' src='/js/jquery/jquery.atwho.js?ver=2013112501'></script>

<link rel="stylesheet" type="text/css" href="/js/jquery/jquery.atwho.css" />

<link rel="alternate" type="application/rss+xml" title="lostchild最新博客" href="http://my.oschina.net/lostchild/rss" />

<link rel="EditURI" type="application/rsd+xml" title="RSD" href="http://my.oschina.net/action/xmlrpc/rsd?space=1397642" />

<link rel="wlwmanifest" type="application/wlwmanifest+xml" href="http://my.oschina.net/action/xmlrpc/wlwmanifest?space=1397642" />

{# echo(header) #}

</head>

<body>

{# echo(content) #}

<body>

</html>

temp.html,繼承master.html

{# ob_start() #}

<script>

alert("hello World")

</script>

{# local header = ob_get_clean() #}

{# ob_start() #}

<table>

{# for k, v in pairs(params) do #}

<tr>

<td>{# echo(k) #}</td>

<td>{# echo(v) #}</td>

</tr>

{# end #}

</table>

{# local content = ob_get_clean() #}

{# include('master.html', {header = header, content = content}) #}

循環十萬次測試渲染速度(阿裡雲最便宜一款vps)

[root@AY130801221248587d02Z ~]# time lua ltemplate.lua temp.html


real 0m1.867s

user 0m1.862s

sys 0m0.004s

總結

由此可見渲染的速度還是非常快的,可以將此原型用於嵌入式設備中的頁面上(用大量js實現的嵌入式設備頁面兼容性不好)。而且嵌入式設備的界面需要簡單明確,所以也不用太豐富的模版功能。

原理很簡單:

1.用lua版的正則把模版內{#與#}之間的內容挖出來,原樣輸出成lua代碼,其它部分則生成使用echo打印到某個緩沖區的lua代碼。

2.將這個生成出來的代碼使用loadstring編譯。

3.通過setfenv實現loadstring後的模擬環境配置(用以提供模版內使用的echo,ob_start等函數,以及傳入的參數)

4.執行這個編譯後的函數即可。

Lua 的詳細介紹:請點這裡
Lua 的下載地址:請點這裡

Copyright © Linux教程網 All Rights Reserved