文档章节

70行lua代码实现一个满足基本要求的模版引擎

乌龟壳
 乌龟壳
发布于 2013/12/22 01:25
字数 788
阅读 5248
收藏 91

以下内容仅供学习交流,未经严格考虑与测试,切勿用于生产环境。

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

© 著作权归作者所有

共有 人打赏支持
乌龟壳
粉丝 111
博文 22
码字总数 13409
作品 0
深圳
程序员
加载中

评论(11)

乌龟壳
乌龟壳

引用来自“hac2009”的评论

Lua 确实很好,我也用它做了一些数据库ETL功能,做了一些数据库字典管理并根据字典自动生成SQL的小工具,做了一个简单的Web服务器,做过中文分词,做过统计分析。小巧、快速,越用越好用,不愧是脚本语言之王
简单用用还好,复杂用法比如涉及到一些特殊的数据类型就有点捉襟见肘了。比如decimal,比如unicode,如果有数据库这些还好,lua一般只是作个中间人,但如果是lua本身去算这些就蛋疼了。
hac2009
hac2009
Lua 确实很好,我也用它做了一些数据库ETL功能,做了一些数据库字典管理并根据字典自动生成SQL的小工具,做了一个简单的Web服务器,做过中文分词,做过统计分析。小巧、快速,越用越好用,不愧是脚本语言之王
玉龙古风
玉龙古风
LUA还是挺好玩的
Momor
Momor
傻鸟都是希望世界只有他们认识的那么一种虫子
ipaomian
ipaomian

引用来自“mmpp33”的评论

应该立法,禁止这些反人类的语言

应该立法,禁止这些反人类的人
阿里狼
阿里狼

引用来自“mmpp33”的评论

应该立法,禁止这些反人类的语言

严重同意,把火星人送到水星上去,淹死他们,哈哈
mmpp33
mmpp33
应该立法,禁止这些反人类的语言
z
zx32342342
seared2008
seared2008
收藏了
Vian
Vian
想学lua很久了,但是实在懒得学17,收藏了有空学习~
最简单的基于js实现的模版引擎

继之前推出的70行代码实现的lua模版引擎后,又遇到了需要在js实现模版引擎的需求,遂实现之 首先是模版引擎的代码 接下来就用一个html页面来说明如何使用 运行结果 至于性能如何?个人项目中...

乌龟壳
2016/12/06
44
0
aspx页面集成工作流引擎api

最近用户在做工作流系统的集成时,总会要求快速的集成到用户的应用系统。 一般一个成熟的工作流软件产品,会有流程设计器,流程引擎,表单设计器,流程管理中心。在流程管理中心能可视化给业...

长平狐
2012/10/11
94
0
模版引擎XTemplate与代码生成器XCoder(源码)

模版引擎XTemplate是一个仿T4设计的引擎,功能上基本与T4一致(模版语法上完全兼容T4,模版头指令部分兼容)。 自己设计模版引擎,就是为了代码生成器、网站模版、邮件模版等多种场合,也就是...

大石头
2010/12/21
0
0
基于Lua实现的脚本和服务器引擎--Node-Lua

Node-Lua是一款基于Lua实现的脚本和服务器引擎,它支持构建海量Lua服务(ContextLua)并以多线程方式运行在多核服务器上,采用了任务多路复用的设计方案,有效利用了多核优势。node-lua致力于构...

socoding
2016/03/17
1K
5
设计一个Web框架,需要的功能

这篇文章是《自己动手设计一个Web框架》文章的续,经过和大家的讨论我总结并归纳一下对《Haweb》这款框架的期待。 首先要感谢各位的热烈讨论,包括线上的还有线下QQ群里的兄弟们。我归纳总结...

哈库纳
2015/11/23
1K
11

没有更多内容

加载失败,请刷新页面

加载更多

下一页

MySQL 乱七八糟的可重复读隔离级别实现

MySQL 乱七八糟的可重复读隔离级别实现 摘要: 原文可阅读 http://www.iocoder.cn/Fight/MySQL-messy-implementation-of-repeatable-read-isolation-levels 「shimohq」欢迎转载,保留摘要,谢...

DemonsI
47分钟前
2
0
Spring源码阅读——2

在阅读源码之前,先了解下Spring的整体架构: 1、Spring的整体架构 1. Ioc(控制反转) Spring核心模块实现了Ioc的功能,它将类与类之间的依赖从代码中脱离出来,用配置的方式进行依赖关系描...

叶枫啦啦
今天
1
0
jQuery.post() 函数格式详解

jquery的Post方法$.post() $.post是jquery自带的一个方法,使用前需要引入jquery.js 语法:$.post(url,data,callback,type); url(必须):发送请求的地址,String类型 data(可选):发送给后台的...

森火
今天
0
0
referer是什么意思?

看看下面这个回答(打不开网页可以把网址复制到搜索栏): https://zhidao.baidu.com/question/577842068.html

杉下
今天
1
0
使用U盘安装CentOS-解决U盘找不到源

1. 使用UltraISO制作CentOS安装盘 如果需要安装带界面的系统,为保证安装顺利,可选择Everything版本的ISO制作安装盘。 2. 在BIOS中选择使用U盘安装 系统启动后,进入安装选择界面,其中有三...

Houor
今天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部