旧文本模板

lua-users home
wiki


[!] 版本通知:以下代码适用于旧版本的 Lua,Lua 4。它在 Lua 5 下无法运行。此页面的最新版本位于 文本模板

对于新的 Lua 程序员来说,一个很好的练习是在 Lua 中实现 Jon Bentley 的 M1 宏处理器 [1]。然后看看 test/examples/www/staff.lua [2],你会发现宏处理器的主要缺点是它们没有数据结构,而且添加数据结构并不难。目标是创建一个名为 template 的函数用于创建模板,以及另一个名为 fillin 的函数,它从表中获取值并将其替换到模板中对应的位置。模板语法非常简单。表成员和全局变量通过用 | 括起来的名称引用,环境变量以 $ 为前缀,函数调用以 @ 为前缀,Lua 代码用 @{ 和 } 括起来。以下是如何使用 templatefillin 的示例。
require'temp.lua'
t1 = template[[
==============================================================================
you can access variables: |v|
or environment variables: $HOME
you can call functions: @concat( list, ', ' )
this list has |list.n| elements
   @strrep( '=', list.n )
   @concat( list )
   @strrep( '=', list.n )
or evaluate code inline
     @{ for i=1,4 do OUT = OUT .." list[".. i .."] = ".. list[i] .."\n" end }
you can access global variables:
This example is from |mjd| at |mjdweb|
@{ x = getn(list) }The Lord High Chamberlain has gotten @getn(list)
things for me this year.
@{ diff = x - 2
   more = 'more'
   if diff == 0 then
     diff = 'no'
   elseif diff < 0 then
     more = 'fewer'
   end
}
That is |diff| |more| than he gave me last year.
values can have other variables: |ref|
==============================================================================
]]
mjd = "Mark J. Dominus"
mjdweb = 'http://perl.plover.com/'
L = {}
for i = 1,5 do tinsert( L, strchar(64+i) ) end
x = {
  v = 'this is v',
  list = L,
  ref = "|mjd| made Text::Template.pm" 
}
-- fill in the template t1 with values in table x
write( fillin( x, t1 ) )
以下是上面代码的输出。 文本模板示例输出 temp.lua 的代码很长,所以我把它放在另一个页面上,并附带行号。 文本模板代码 请注意,此代码需要 Lua 4.1(beta)。template 函数会从模板字符串中删除所有函数调用和 Lua 代码,并用 Magic 全局变量的名称替换它们。对于上面的示例,这就是 template 返回的内容。
==============================================================================
you can access variables: |v|
or environment variables: /home/administrator
you can call functions: |2concat|
this list has |1list| elements
   |3strrep|
   |4concat|
   |5strrep|
or evaluate code inline
     |7ANY|
you can access global variables:
This example is from |mjd| at |mjdweb|
|8ANY|The Lord High Chamberlain has gotten |6getn|
things for me this year.
|9ANY|
That is |diff| |more| than he gave me last year.
values can have other variables: |ref|
==============================================================================
template 还会将它从模板字符串中删除的所有函数调用和 Lua 代码包装在一个表中,该表以 Magic 变量名称为索引,并将所有 Magic 变量指向该表。对于上面的示例,以下是 template 生成的代码,并使用 dostring 进行评估。
local Magic = settype( {}, newtype'magic' )
Magic['1list'] = function()
  local self=globals()
  return list.n --
end
setglobal('1list', Magic )
Magic['2concat'] = function()
  local self=globals()
  return concat( list, ', ' ) --
end
setglobal('2concat', Magic )
Magic['3strrep'] = function()
  local self=globals()
  return strrep( '=', list.n ) --
end
setglobal('3strrep', Magic )
Magic['4concat'] = function()
  local self=globals()
  return concat( list ) --
end
setglobal('4concat', Magic )
Magic['5strrep'] = function()
  local self=globals()
  return strrep( '=', list.n ) --
end
setglobal('5strrep', Magic )
Magic['6getn'] = function()
  local self=globals()
  return getn(list) --
end
setglobal('6getn', Magic )
Magic['7ANY'] = function()
  local OUT=''
  local self=globals()
  do  for i=1,4 do OUT = OUT .." list[".. i .."] = ".. list[i] .."\n" end  end
  return OUT
end
setglobal('7ANY', Magic )
Magic['8ANY'] = function()
  local OUT=''
  local self=globals()
  do  x = getn(list)  end
  return OUT
end
setglobal('8ANY', Magic )
Magic['9ANY'] = function()
  local OUT=''
  local self=globals()
  do  diff = x - 2
   more = 'more'
   if diff == 0 then
     diff = 'no'
   elseif diff < 0 then
     more = 'fewer'
   end
 end
  return OUT
end
setglobal('9ANY', Magic )
fillin 函数接受一个值表和从 template 返回的字符串,并使用 gsub 填充这些值。在此之前,它将值表设置为全局变量表,并为 nil 值设置 getglobal 标签方法。因此,如果在值表中找不到变量,它会尝试在 sharedvars 表中查找,如果失败,则会查找真正的全局变量表。这看起来过于复杂,但它允许模板中的代码片段访问值表和全局变量,就像它们在作用域内一样。它还会调用与它找到的任何 Magic 变量关联的函数。如果有更好的方法,请修复此问题。
最近更改 · 偏好设置
编辑 · 历史记录
最后编辑于 2007 年 5 月 28 日下午 8:45 GMT (差异)