使用Lua编写Web端模板引擎的实例代码分享
ltemplate.lua
localinsert=table.insert
localremove=table.remove
localconcat=table.concat
localformat=string.format
localloaded={}
localpartten="(.-){#([^#].-[^#])#}()"
localcontent={}
localcur_content=nil
localfunctionob_start()
cur_content={}
insert(content,cur_content)
end
localfunctionob_get_clean()
localret=concat(cur_content)
remove(content)
cur_content=content[#content]
returnret
end
localfunctionecho(value)
insert(cur_content,value)
end
localfunctioninclude(path,params)
localbitcode=loaded[path]
ifnotbitcodethen
localfp=io.open(path,"rb")
localtemplate=fp:read('*a')
fp:close()
localresults={}
locallast_endpos=0
foroutside,inside,endposintemplate: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
localenv={
include=include,
echo=echo,
ob_start=ob_start,
ob_get_clean=ob_get_clean
}
setmetatable(env,{__index=function(tb,k)
returnparams[k]or_G[k]
end})
setfenv(bitcode,env)
bitcode()
end
fori=1,100000do
ob_start()
include(arg[1],{
params={
a='1234',
b='4321'
}
})
ob_get_clean()
end
master.html
<!DOCTYPEhtmlPUBLIC"-//W3C//DTDXHTML1.0Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<htmllang='zh-CN'xml:lang='zh-CN'xmlns='http://www.w3.org/1999/xhtml'>
<head>
<metahttp-equiv="Content-Type"content="text/html;charset=UTF-8"/>
<metahttp-equiv="Content-Language"content="zh-CN"/>
<metaname="robots"content="index,follow"/>
<linkrel="shortcuticon"type="image/x-icon"href="/img/favicon.ico"/>
<title>child'spersonalpage-开源中国社区</title>
<linkrel="stylesheet/less"href="http://my.oschina.net/lostchild/styles.less?ver=20131219&date=20131110185237"type="text/css"media="screen"/>
<linkrel="stylesheet"href="/js/2012/poshytip/tip-yellowsimple/tip-yellowsimple.css"type="text/css"/>
<linkrel="stylesheet"type="text/css"href="/js/2011/fancybox/jquery.fancybox-1.3.4.css"media="screen"/>
<scripttype="text/javascript"src="/js/2012/jquery-1.7.1.min.js"></script>
<scripttype="text/javascript"src="/js/2012/jquery.form.js"></script>
<scripttype="text/javascript"src="/js/2011/fancybox/jquery.fancybox-1.3.4.pack.js"></script>
<scripttype="text/javascript"src="/js/2012/poshytip/jquery.poshytip.min.js"></script>
<scripttype="text/javascript"src="/js/2011/oschina.js?ver=20121007"></script>
<scripttype="text/javascript"src="/js/2012/less-1.3.0.min.js"></script>
<scripttype="text/javascript"src="/js/scrolltopcontrol.js"></script>
<scripttype='text/javascript'src='/js/jquery/jquery.atwho.js?ver=2013112501'></script>
<linkrel="stylesheet"type="text/css"href="/js/jquery/jquery.atwho.css"/>
<linkrel="alternate"type="application/rss+xml"title="lostchild最新博客"href="http://my.oschina.net/lostchild/rss"/>
<linkrel="EditURI"type="application/rsd+xml"title="RSD"href="http://my.oschina.net/action/xmlrpc/rsd?space=1397642"/>
<linkrel="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("helloWorld")
</script>
{#localheader=ob_get_clean()#}
{#ob_start()#}
<table>
{#fork,vinpairs(params)do#}
<tr>
<td>{#echo(k)#}</td>
<td>{#echo(v)#}</td>
</tr>
{#end#}
</table>
{#localcontent=ob_get_clean()#}
{#include('master.html',{header=header,content=content})#}
循环十万次测试渲染速度(阿里云最便宜一款vps)
[root@AY130801221248587d02Z~]#timelualtemplate.luatemp.htmlreal0m1.867s
user0m1.862s sys0m0.004s
总结
由此可见渲染的速度还是非常快的,可以将此原型用于嵌入式设备中的页面上(用大量js实现的嵌入式设备页面兼容性不好)。而且嵌入式设备的界面需要简单明确,所以也不用太丰富的模版功能。
原理很简单:
1.用lua版的正则把模版内{#与#}之间的内容挖出来,原样输出成lua代码,其它部分则生成使用echo打印到某个缓冲区的lua代码。
2.将这个生成出来的代码使用loadstring编译。
3.通过setfenv实现loadstring后的模拟环境配置(用以提供模版内使用的echo,ob_start等函数,以及传入的参数)
4.执行这个编译后的函数即可。