加入收藏 | 设为首页 | 会员中心 | 我要投稿 PHP编程网 - 黄冈站长网 (http://www.0713zz.com/)- 数据应用、建站、人体识别、智能机器人、语音技术!
当前位置: 首页 > 教程 > 正文

80行Lua代码达成一个满足基本要求的模版引擎

发布时间:2021-12-13 10:53:33 所属栏目:教程 来源:互联网
导读:80行Lua代码实现一个满足基本要求的模版引擎,以下内容仅供学习交流,未经严格考虑与测试,切勿用于生产环境。 ltemplate.lua local insert = table.insert local remove = table.remove local concat = table.concat local format = string.format local lo

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'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.执行这个编译后的函数即可。

(编辑:PHP编程网 - 黄冈站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    热点阅读