Python模板代码库Cheetah介绍及使用

cheetah文档

1.引言

1.1什么是cheetah

Cheetah 是一个 Python 驱动的模板引擎和代码生成器。它可以用作独立的实用程序或与其他工具结合使用。

  • 生成 HTML、SGML、XML、SQL、Postscript、表单电子邮件、LaTeX 或任何其他基于文本的格式。它还被用于生成 Python、Java 和 PHP 源代码。
  • 使模板编写者可以在其模板中完全访问任何 Python 数据结构、模块、函数、对象或方法。
  • 一个模板可以继承另一个模板并有选择地重新实现它的部分。编译后的模板是一个 Python 类

1.2编写目的

编写《Cheetah文档》的目的是为了了解cheetah模板代码的编写方法以及调用方法,通过对工具库的应用提高源代码阅读能力和实践应用能力。

2.总述

Cheetah模板语言不同于其他的HTML模板语言以标签的形式使用占位符等一系列操作 这也使得它具有更广泛的应用性 HTML 样式的标签很难与真正的 HTML 标签区分开来,HTML 样式的标签在渲染的 HTML 中不可见当出现问题时,HTML 样式标签通常会导致 HTML 无效Cheetah 标签比 HTML 样式标签更简洁且更易于理解

3.模板文件

3.1模板文件介绍

模板文件的通常后缀为.tmpl 它是由模板编写人员进行维护 主要组成为:

  1. 文本
  2. 占位符:在填充模板时将查找的变量
  3. 指令:在模板被填充时要执行的命令,或者是给Cheetah编译器的指令

3.2模板的使用

模板代码可以有两种用途:

  1. 编译模板
  2. 填充模板

其中编译是填充模板的先决条件

Cheetah采用模板定义并生成 Python 代码来创建填充字符串 在测试用例中有完整的步骤

3.3模板的用途

下面介绍一个邮件模板来说明:

假设一名学生需要发送一封邮件给老师 提出请假一天的请求:

Dear Mr.LIU:
	I need to take a day off because of something, please approve!
												Your student:Lihua
												2022.10.25

为了方便 可以将这个格式提取成模板 每次只需要更换对应的变换信息就可以达到简化的目的:

Dear $teacher:
	I need to take a day off because of $things, please approve!
												Your student:$student
												$date

同理 当我们编写代码时 可能一套完整的项目需要在相同的位置显示不同的信息从而成为新的项目

这时就需要用到模板代码了

4.开始使用

99%的cheetah是用python编写的。有一个小的C模块({_namemapper.so})用于提升速度,但如果C模块不可用,cheetah会自动回退到Python等效类({NameMapper.py})。

4.1安装

在命令提示符下运行

pip install CT3

如若提示报错可加入阿里源

pip install CT3 -i http://mirrors.aliyun.com/pypi/simple --trusted-host mirrors.aliyun.com

4.2测试安装

cheetah test

在命令行输入上述命令 若没有报错 则证明成功安装cheetah

5.cheetah语法

5.1注释

在cheetah模板中使用:

  1. ##作为单行注释
  2. *#作为多行注释

注意:当遇到类似#include的情况时 需要加入\#进行转义

例子:

单行注释:

##这是一个单行注释
$var ##这是一个占位符

多行注释:

#*
  这是一些多行注释
*#

5.2复杂表达式的输出

#echo 表达式

Example:
She is #echo ','.join(['so']*5) # beautiful
OutPut:
She is so,so,so,so,so beautiful

5.3 执行不带输出表达式

#silent 表达式

Example:
#silent $numList.Sort()

5.4单行 #if

#if 表达式1 then 表达式2 else 表达式3#

该表达式类似于c语言中的三元运算符

  1. 如果表达式1的值为true 则计算表达式2并输出
  2. 反之则计算表达式3并输出

注意:尾部的#代表指令的结束

5.5缓存占位符

$var 		##普通占位符
$*var 		##静态占位符 仅在开始时加载 之后只要实例在内存中便会永久缓存
$*5* var	##设置缓存时间 默认单位为分钟 当前缓存5分钟

注意:5分钟缓存指的是每5分钟一次 当达到时间限制时 不论模板是否频繁填充

都会再次查找

5.6缓存整个区域

#cache [id=EXPR] [timer=EXPR] [test=EXPR]
#end cache

{#cache} 指令用于缓存模板中的内容区域。

在运算区域内的占位符和指令后,该区域将缓存为单个单元。

缓存区域比单个缓存占位符更加灵活 可以使用占位符或表达式指定刷新间隔

也可跟据其他条件不在特定间隔刷新

5.7#raw

#raw
#end raw

在标记内对模板定义的任何部分都将逐字打印而不是解析占位符

这对调试cheetah非常有用

5.8#include

#include [raw] FILENAME_EXPR
#include [raw] source=STRING_EXPR

{#include} 指令用于包含来自模板定义外部的文本

Cheetah将监视对所包含文件的更改,并根据需要进行更新。

参数“{raw}”可用于禁止分析。

#include raw "includeFileName.txt"
#include raw source=$myParseText

5.9#slurp

{#slurp} 指令占用其所在行上的尾随换行符,将下一行连接到当前行。

Example:
#for $i in range(5)
$i #slurp
#end for
Output:
0 1 2 3 4


UnSlurp:
#for $i in range(5)
$i
#end for
Output:
0
1
2
3
4


5.10过滤器

#filter FILTER_CLASS_NAME
#filter $PLACEHOLDER_TO_A_FILTER_INSTANCE
#filter None

占位符的输出可以经过过滤器

在默认情况下:

  1. 过滤器仅返回占位符值的字符串形式
  2. 若值为None 则返回空字符串

示例:

${占位符名称, maxlen=20}

在此情况下 设定值的长度最大为20 若超出则截断该值

5.11#import和#from指令

{#import} 和 {#from} 指令用于使外部 Python 模块或对象可供占位符使用。

语法与 Python 中的导入语法相同。

导入的模块对生成的 Python 类中的所有方法都是全局可见的。

#import math
#import math as mathModule
#from math import sin, cos

5.12#set

#set [global] $var = EXPR

结合5.8#include 我们做以下测试:

已知 include可以将text文件进行占位符或命令解析

那么:

1.新建一个text 命名为:values.txt

#set global $var = 1096

#for $i in range(5)
$i #slurp
#end for

不难理解 我们设置了一个全局占位符var并赋值为1096

并且目标实现一个for循环

2.新建模板文件 命名为main.tmpl

#include "values.txt"

#echo $var

目的是包含values.txt 并且尝试输出全局占位符var的值

3.测试结果:

0 1 2 3 4
1096

5.13#del

#del $var

{#del} 与 {#set} 相反。它删除 { 本地} 变量。

只能删除局部变量。不能用于删除 {#set global} 变量、searchList 变量或任何其他类型变量的指令。

5.14#attr

#attr $var = 表达式

Example:
#attr $title = "Rob Roy"
#attr $author = "Sir Walter Scott"
#attr $version = 123.4

{#attr} 指令在生成的 Python 类中创建类属性。它应该用于分配简单的Python文本,如数字或字符串

此模板或任何子模板都可以输出以下值

5.15#def

#def METHOD[(ARGUMENTS)]
#end def

{#def} 指令用于在生成的 Python 类中定义新方法,或覆盖超类方法

它类似于 Python 的 {def} 语句。该指令本身不会产生任何输出。

但是,只要稍后由 $占位符 调用该方法,该方法的内容就会插入到输出中(并执行指令)

#def myMeth()
This is the text in my method
$a $b $c(123)
#end def

## 如何调用它..
$myMeth()


也可以省略括号
#def myMeth
This is the text in my method
$a $b $c(123)
#end def

## 如何调用它..
$myMeth

也可以定义方法需要传入的参数:

#def myMeth($a, $b=1234)  ##与Python一致 可以设置参数并赋予默认值
This is the text in my method
$a - $b
#end def


$myMeth(1)

Output:
This is the text in my method
1 - 1234

5.16#block … #end

#block testBlock
Text in the contents
area of the block directive
#if $testIt
$getFoo()
#end if
#end block testBlock

{#block} 指令允许标记模板中可以选择性地在子类中重新实现的部分。这对于更改模板的一部分而无需复制粘贴和编辑整个内容非常有用。

{#block} 指令可以嵌套到任何深度。:

#block outerBlock
Outer block contents

#block innerBlock1
inner block1 contents
#end block innerBlock1

#block innerBlock2
inner block2 contents
#end block innerBlock2

#end block outerBlock

6.流程控制

6.1#for … #end for

#for $var in EXPR
#end for

{#for} 指令遍历一个序列。语法与 Python 相同,但请记住变量前的 {$}

例如:实现一个列表

<TABLE>
#for $client in $service.clients
<TR>
<TD>$client.surname, $client.firstname</TD>
<TD><A HREF="mailto:$client.email" >$client.email</A></TD>
</TR>
#end for
</TABLE>

遍历字典的键值:

#for $key, $value in $dict.items()
$key: $value
#end for

这个“#end for”标签共享最后一行,以避免在每个连字符后引入换行符。

#for $i in range(15)
$i - #end for
##或者:
#for $i in $range(15)
$i - #slurp
#end for

在每个数字后加字符:

#set $sep = ''
#for $name in $names
$sep$name
#set $sep = ', '
#end for

##或者:
#echo ', '.join($names) ##在5.2提到过

6.2#repeat … #end

#repeat EXPR
#end repeat

注意:若EXRP为0或负数则循环执行0次

#repeat $times + 3
She loves me, she loves me not.
#end repeat
She loves me.

##Output:when $times = 1
She loves me, she loves me not.
She loves me, she loves me not.
She loves me, she loves me not.
She loves me, she loves me not.
She loves me.

6.3#while … #end while

#while EXPR
something
#end while

{#while} 与 Python 的 {while} 语句相同。它后面可以跟任何布尔表达式

**注意:**如果while无限循环 则一直计算到计算机内存不足为止

6.4#if … #else if … #else … #end if

#if EXPR ##表达式为真,除非它的计算结果为 0、''、None、空列表或空字典。
#else if EXPR
#elif EXPR ##{#elif} 是 {#else if} 的同义词。
#else
#end if

6.5#unless … #end

#unless EXPR
#end unless

{#unless} 与 {#if} 相反:如果条件为 { false},则执行。

有时这更方便。{#unless EXPR} 等价于 {#if not (EXPR)}。

6.6#break 和 #continue

#break
#continue

这些指令在 Python 中使用。

  1. {#break} 将提前退出 {#for} 循环
  2. {#continue} 将立即跳转到 {#for} 循环中的下一个迭代

例如:输出列表将不包含“10 -”

#for $i in range(15)
#if $i == 10
  #continue
#end if
$i - #slurp
#end for

如果找到等于“Joe”的名称,循环将退出

#for $name in $names
#if $name == 'Joe'
  #break
#end if
$name - #slurp
#end for

6.7#pass

#pass

{#pass} 指令与 Python 的 {pass} 语句相同:它什么都不做。当语法上需要语句但程序不需要操作时,可以使用它。

#if $A and $B
   do something
#elif $A
  #pass
#elif $B
  do something
#else
  do something
#end if

6.8#stop

#stop

{#stop} 指令用于在某个点停止处理模板。输出将显示{仅}到目前为止已处理的内容。

当在 {#include} 中调用 {#stop} 时,它会跳过包含的其余代码并从 {#include} 指令之后继续。

同样,当在 {#def} 或 {#block} 中调用 {#stop} 时,它只会停止 {#def} 或 {#block}。

示例:

A cat
#if 1
  sat on a mat
  #stop
  watching a rat
#end if
in a flat.
##output
A cat
  sat on a mat
  
==========================  
  
A cat
#block action
  sat on a mat
  #stop
  watching a rat
#end block
in a flat.
##Output
A cat
  sat on a mat
in a flat.

6.9#return

#return

这在 Python 中使用。{#return} 将退出当前方法,默认返回值为 {None} 或指定的值。它只能在 {#def} 或 {#block} 内使用。

7.异常处理

7.1#try … #except …

#try
  $mightFail()
#except
  It failed
#end try

7.2#try … #except … #end try

#try
  $mightFail()
#except AssertionError
  They're not the same!
#end try

7.3#assert

#try
  #assert $x == $y
#except AssertionError
  They're not the same!
#end try

7.4#finally

#try
  $mightFail()
#finally
  $cleanup()
#end try

7.5#errorCatcher 和 ErrorCatcher 对象

#errorCatcher CLASS
#errorCatcher $PLACEHOLDER_TO_AN_ERROR_CATCHER_INSTANCE

{ErrorCatcher} 是一个调试工具,可以捕获 {$占位符} 标签内发生的异常,并向开发人员提供可定制的警告。

通常,第一个缺失的命名空间值会引发 {NameMapper.NotFound} 错误并停止填充模板。这需要开发者在不看到后续输出的情况下按顺序解决异常。

启用 {ErrorCatcher} 后,开发人员可以立即查看所有异常以及它们周围的模板输出。

#errorCatcher Echo
#set $iExist = 'Here I am!'
Here's a good placeholder: $iExist
Here's bad placeholder: $iDontExist ##未定义

##output:
Here's a good placeholder: Here I am!
Here's bad placeholder: $iDontExist

测试用例

1.配置文件的代码生成

1.1模板代码分析与参数传入

FACE生成IOSConfig.xml用到的模板代码:

#####################################################################################################
## DISTRIBUTION STATEMENT A. Approved for public release; distribution is unlimited.
## 
## Product produced under DoD SENSIAC contract HC104705D4000 under the sponsorship of the Defense
## Technical Information Center, ATTN: DTIC-AI, 8723 John J. Kingman Rd., Ste 0944, Fort Belvoir, VA
## 22060-6218.  SENSIAC is a DoD Information Analysis Center Sponsored by the Defense Technical
## Information Center.
## 
## HANDLING AND DESTRUCTION NOTICE - Comply with distribution statement and destroy by any method that
## will prevent disclosure of the contents or reconstruction of the document.
######################################################################################################
<?xml version="1.0" encoding="ISO-8859-1"?>

<!--
 ${filename} - AUTO GENERATED
 Generated with the Modeling Tools for FACE Software Development (MTF) - Vanderbilt University#if $generateTimestamp#
 ${timestamp}#end if
 
#for $marking in $productMarkings
 ${marking}
#end for
 Insert project specific header here.
-->

<IOSLConfig xmlns="http://www.example.org/IOServLibSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
#for $io_config in $io_configs
	<Connection_Conf>
		<ConnectionName>${io_config.connectionname}</ConnectionName>
		<ConnectionType>${io_config.connectiontype}</ConnectionType>
		<ConnectionDirection>${io_config.connectiondirection}</ConnectionDirection>
		<CreateConnection>${io_config.createconnection}</CreateConnection>
		<PortName>${io_config.portname}</PortName>
		<MessageSize>${io_config.messagesize}</MessageSize>
		<MessageRange>${io_config.messagerange}</MessageRange>
		<RefreshPeriod>${io_config.refreshperiod}</RefreshPeriod>
		<Reliability>${io_config.reliability}</Reliability>
		<ReadWriteBehavior>${io_config.readwritebehavior}</ReadWriteBehavior>
		<QueueDiscipline>${io_config.queuediscipline}</QueueDiscipline>
		<ConnectionDomain>${io_config.connectiondomain}</ConnectionDomain>
		<SocketType>${io_config.sockettype}</SocketType>
		<ReceiveFlag>${io_config.receiveflag}</ReceiveFlag>
		<SendFlag>${io_config.sendflag}</SendFlag>
		<SourceAddress>${io_config.sourceaddress}</SourceAddress>
		<DestinationAddress>${io_config.destinationaddress}</DestinationAddress>
		<SourcePort>${io_config.sourceport}</SourcePort>
		<DestinationPort>${io_config.destinationport}</DestinationPort>
		<IOType>${io_config.iotype}</IOType>
#if $io_config.iotype_config
#if $io_config.iotype_config.type == "Serial"
		<SerialIO>
			<ChannelNumber>${io_config.iotype_config.chan_num}</ChannelNumber>
			<Mode>${io_config.iotype_config.mode}</Mode>
			<BaudRate>${io_config.iotype_config.baud_rate}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值