代码模板引擎
功能介紹
mkTpl是一個基于Python編寫的模板引擎包. 初始版本發(fā)布于2017年, 當(dāng)時開發(fā)該模板引擎是為了在嵌入式儀表開發(fā)過程中梳理軟件配置, 以便可以生成配置代碼, 避免手動整理配置參數(shù), 極大提升開發(fā)工作效率. 后續(xù)開發(fā)過程中有幾次不同程度的優(yōu)化升級, 引入了用戶字定義代碼與函數(shù)功能, 拓展了模板引擎的應(yīng)用范圍, 目前mkTpl包已在多個項目中引用, 對開發(fā)效率有顯著提升.
環(huán)境搭建
- 安裝python version > 3.0以上版本
- 安裝mkTpl軟件包
- 安裝需要使用的軟件包(xlrd/PyYAML/xml等, 未使用可不安裝)
代碼實例
import mkTplctx = {'測試1': 12345, '測試2': 67890} template = {'test.tpl.c': ['./tpl', './gen', 'test.gen.c']}# 實例化模板引擎 tplobj = mkTpl.mktpl() # 加入數(shù)據(jù)庫 tplobj.addlib('ctx', ctx) # 導(dǎo)入模板, 生成代碼 tplobj.setTemplate(template)模板語法
在代碼實例中字典template有一個值: test.tpl.c, 這里的test.tpl.c就是需要生成的代碼模板, 只有導(dǎo)入了模板, 代碼引擎才能根據(jù)模板和數(shù)據(jù)庫導(dǎo)出用戶需要的代碼. 模板需要提供所在位置與生成代碼存放位置以及生成代碼文件名, 模板引擎實際不會關(guān)注生成的文件格式, 這里只依賴用戶定義, 理論上可以生成任意用戶定義的文本文件.
針對模板的格式有一定要求, 只有按照要求定義的模板, 模板引擎才能解析. 實際代碼生成的過程可以理解成對文件的讀寫過程, 單獨對文件讀寫大家應(yīng)該都接觸過, 如下實例:
# 以a+屬性打開一個文件 text.c file = open('text.c', a+)# 讀取文本內(nèi)容 lines = file.readlines()# 寫入hello world! file.write('hello world!')file.close()而模板引擎的作用就是解析模板, 生成文件讀寫的代碼, 再運行生成的代碼即可獲得想要的最終目標(biāo)代碼. 這里很有意思, 代碼并不是事先寫好的, 而是模板引擎寫的. Python是一門解釋性的語言, 剛好可以完成上述的功能.
- 模板實例: test.tpl.c
- 生成代碼: test.gen.c
函數(shù)
在<%%>中定義函數(shù), 以def起始的代碼會默認(rèn)識別為函數(shù)定義, 函數(shù)直到出現(xiàn)一行靜態(tài)代碼結(jié)束. 在定義函數(shù)時, 函數(shù)存在一個默認(rèn)參數(shù)info, 在不使用輸出文件功能時可不定義, 若定義參數(shù)info使用的時候需要加上參數(shù)info, 其他用戶參數(shù)可自行定義, 實例如下:
函數(shù)定義: <%def test_func(info):%> <% print("hello world.")%> <% ~write in output file: hello world.%>函數(shù)使用: <%test_func(info)%>特殊標(biāo)識 <%%>
模板語法動態(tài)模板代碼完全支持python語法, 但動態(tài)代碼需要使用<%%>標(biāo)記, 否則默認(rèn)為靜態(tài)代碼.
example:
<%for key in ctx:%> <% print('ctx key: %s'% key)%>特殊標(biāo)識: ~ (info.write)
example:
<%for key in ctx:%> <% ~test coding: ${key}, ${ctx[key]}%>or<%for key in ctx:%> <% info.write("test coding: %s, %s\n"%(key, ctx[key]))%>實例中給出了兩段代碼, 實際結(jié)果是一樣的, ~ 與 info.write 擁有相同功能, ~是優(yōu)化后的表現(xiàn), 使模板編輯更方便高效.
關(guān)鍵字: User Coding Symbol
User Coding Symbol字段設(shè)計的時候參考了DaVinci生成代碼的功能, 生成代碼的時候可以識別User Coding Symbol字段, 在該字段注釋內(nèi)部用戶可以編寫自定義代碼, 模板引擎會主動merge用戶代碼與生成的代碼, 該功能的引入, 有效的擴(kuò)大了mkTpl的應(yīng)用范圍, 有了該功能后, 再不局限于設(shè)計之初的想法, 不但能應(yīng)用于配置代碼的生成, 也可應(yīng)用于大量重復(fù)邏輯代碼的編寫中. 實際開發(fā)過程中往往會遇到結(jié)構(gòu)類似, 但是細(xì)節(jié)上又存在一些不確定性的差異, 原來的模板引擎功能很難實現(xiàn)這種代碼的整理, 引入User Coding Symbol后, 使得該場景下的模板實現(xiàn)成為可能.
在使用User Coding Symbol的時候需要注意, 實際有兩種方式使用:
- 單例模式
<%User Coding Symbol: name%>
適用于單個User Coding Symbol
- 迭代模式
<%User Coding Symbol: @nameVar%>
適用于多個User Coding Symbol
特殊標(biāo)識: ${}
${}最常用, 變量的替換需要使用${}標(biāo)記, 變量放入大括號內(nèi), 變量之前可以帶數(shù)字, 用于定義寫入字符長度與對其功能(正負(fù)分別表示不同方向的對其).
<% ~test coding: ${10key}, ${-6ctx[key]}%>使用實例
在儀表項目中, Warning與VfcMgr模塊中應(yīng)用mkTpl做了部分代碼生成工作, 以VfcMgr為例, 應(yīng)用過程如下:
在VFC功能開發(fā)中, 有眾多的Activator, 每個都包含大量的信號邏輯判斷功能, 為了解決開發(fā)者在這樣巨量的邏輯中迷失, 引入yaml配置邏輯功能, 所有相關(guān)的信號邏輯表達(dá)式全部在yaml文件上統(tǒng)一配置. 再配合部分靜態(tài)代碼, 實現(xiàn)邏輯功能全配置, 不用用戶單獨編寫額外代碼.
有關(guān)LC -> VFC -> PNC之間的關(guān)系通過excel配置, 再由mkTpl加上模板一并導(dǎo)出關(guān)系配置表.
yaml配置實例:
ObjMntr:PinToDrvForHmiCen: # VFC Activation Criteria# ( {PinToDrvCod}ChangeFromAnyToX (X=CodVld.Inact_Active) )# OR( {PinToDrvCodHmiReq}ChangeToOther ) )# AND{VehModMngtGlbSafe1}NotEqualToX(X=UsgModSts.UsgModSts1_UsgModAbdnd) )# VFC Deactivation Criteria# ( VFCTimeOutDelay [sec] = 3 )Delay: 3000Tx:PinToDrvCodCodVld:Type: uint8Condition: [ Prev.PinToDrvCodCodVld != Curr.PinToDrvCodCodVld, Curr.PinToDrvCodCodVld == Inact_Active ]PinToDrvCodHmiReq:Type: PinToDrvCodHmiReqCondition: [ Prev.PinToDrvCodHmiReq != Curr.PinToDrvCodHmiReq ]LogicalExpression:ActyLE0: CC_PinToDrvCodCodVld_Condition_0 && CC_PinToDrvCodCodVld_Condition_1ActyLE1: CC_PinToDrvCodHmiReq_Condition_0ActRule: LE_ActyLE0 || LE_ActyLE1yaml軟件模板:
/*** Tx signals interface.*/ <%sigsTab = []%> <%for lc in mrkChgMap['ObjMntr']:%> <% if 'Tx' in mrkChgMap['ObjMntr'][lc]:%> <% for sg in mrkChgMap['ObjMntr'][lc]['Tx']:%> <% a = False%> <% if sg not in sigsTab:%> <% sigsTab.append(sg)%> <% if sg in sglib['sg']['tx']:%> <% a = True%> <% ~#define VfcMgr__Read_Write_${sg}() (SigSer_${sg})%> <% for gp in sglib['gp']['tx']:%> <% if sg in sglib['gp']['tx'][gp]:%> <% a = True%> <% if sglib['gp']['tx'][gp][sg]['index'] != -1:%> <% ~#define VfcMgr__Read_Write_${sg}() (SigSer_${gp}[${sglib['gp']['tx'][gp][sg]['index']}])%> <% else:%> <% ~#define VfcMgr__Read_Write_${sg}() (SigSer_${gp}.${sg})%> <% else:%> <% a = True%> <% if a == False:%> <% print("Sg: %s is error."%sg)%> ...yaml生成代碼:
#define VfcMgr__nTimeoutDly_PinToDrvForHmiCen ( (uint16)(3000ul / VfcMgr__nMainCycleCntr) )#define VfcMgr__Read_Write_PinToDrvCodCodVld() (SigSer_PinToDrvCod.PinToDrvCodCodVld) #define VfcMgr__Read_Write_PinToDrvCodHmiReq() (SigSer_PinToDrvCodHmiReq)#define VfcMgr__boPinToDrvForHmiCen_PinToDrvCodCodVld_Condition_0 ( VfcMgr__PinToDrvCodCodVld != VfcMgr__Read_Write_PinToDrvCodCodVld() ) #define VfcMgr__boPinToDrvForHmiCen_PinToDrvCodCodVld_Condition_1 ( VfcMgr__Read_Write_PinToDrvCodCodVld() == Inact_Active ) #define VfcMgr__boPinToDrvForHmiCen_PinToDrvCodHmiReq_Condition_0 ( VfcMgr__PinToDrvCodHmiReq != VfcMgr__Read_Write_PinToDrvCodHmiReq() )#define VfcMgr__boPinToDrvForHmiCen_ActyLE0 ( VfcMgr__boPinToDrvForHmiCen_PinToDrvCodCodVld_Condition_0 && VfcMgr__boPinToDrvForHmiCen_PinToDrvCodCodVld_Condition_1 ) #define VfcMgr__boPinToDrvForHmiCen_ActyLE1 ( VfcMgr__boPinToDrvForHmiCen_PinToDrvCodHmiReq_Condition_0 )#define VfcMgr__boActRule_PinToDrvForHmiCen ( VfcMgr__boPinToDrvForHmiCen_ActyLE0 || VfcMgr__boPinToDrvForHmiCen_ActyLE1 )excel配置:
excel軟件模板:
<%~const VfcMgr__tstLCsAttrs VfcMgr__rastLCsAttrs_Tab[VfcMgr_nenNrOfLCs] = {%> <%for lc in VFCInfo:%> <% u8VFCIndex = str(VFC2PNC[VFCInfo[lc]['VFCName']]['VFCID'] + 100)[1:]%> <% u8PNCIndex = str(VFC2PNC[VFCInfo[lc]['VFCName']]['PNC'] + 100)[1:]%> <% na = lc.replace('-', '')%> <% na = na.replace(' ', '')%> <% u8UsageMode = VFCInfo[lc]['Usagemode']%> <% u8CarMode = VFCInfo[lc]['CarMode']%> <% pfLCActyFnct = 'VfcMgr__v'+na+'Detect'%> <% ~ {VfcMgr_nVFC${u8VFCIndex}, VfcMgr_nPNC${u8PNCIndex}, ${3u8UsageMode}, ${3u8CarMode}, ${-52pfLCActyFnct}}, /*!> ${lc} */%> };excel生成代碼:
const VfcMgr__tstLCsAttrs VfcMgr__rastLCsAttrs_Tab[VfcMgr_nenNrOfLCs] = {{VfcMgr_nVFC41, VfcMgr_nPNC16, 7, 31, VfcMgr__vV2XCtrlForHmiCenDetect }, /*!> V2XCtrlForHmiCen */{VfcMgr_nVFC41, VfcMgr_nPNC16, 15, 31, VfcMgr__vDrvrHmiMgrPlatform1ForDrvrHmiDetect }, /*!> DrvrHmiMgrPlatform1ForDrvrHmi */{VfcMgr_nVFC41, VfcMgr_nPNC16, 15, 31, VfcMgr__vDrvrHmiMgrPlatform2ForDrvrHmiDetect }, /*!> DrvrHmiMgrPlatform2ForDrvrHmi */{VfcMgr_nVFC41, VfcMgr_nPNC16, 15, 31, VfcMgr__vInfotainmentModMgr_InfotainmentPushDetect }, /*!> InfotainmentModMgr_InfotainmentPush */{VfcMgr_nVFC41, VfcMgr_nPNC16, 7, 9, VfcMgr__vVehSurrndgsVisnCtrlDetect }, /*!> VehSurrndgsVisnCtrl */{VfcMgr_nVFC41, VfcMgr_nPNC16, 15, 9, VfcMgr__vVehSurrndgsVisnAddlDetect }, /*!> VehSurrndgsVisnAddl */{VfcMgr_nVFC41, VfcMgr_nPNC16, 15, 31, VfcMgr__vFaceIdnMgrDetect }, /*!> FaceIdnMgr */{VfcMgr_nVFC16, VfcMgr_nPNC17, 15, 31, VfcMgr__vLeReCenLockUnlockBtnDetect }, /*!> LeReCenLockUnlockBtn */{VfcMgr_nVFC16, VfcMgr_nPNC17, 31, 31, VfcMgr__vRiReCenLockUnlockBtnDetect }, /*!> RiReCenLockUnlockBtn */{VfcMgr_nVFC10, VfcMgr_nPNC18, 7, 31, VfcMgr__vExteriorLightShow_ExteriorLightingDetect }, /*!> ExteriorLightShow_ExteriorLighting */{VfcMgr_nVFC10, VfcMgr_nPNC18, 15, 31, VfcMgr__vWelcomeLightDIYDetect }, /*!> WelcomeLightDIY */{VfcMgr_nVFC21, VfcMgr_nPNC19, 31, 31, VfcMgr__vLePwrSldgDoorBtnDetect }, /*!> LePwrSldgDoorBtn */{VfcMgr_nVFC21, VfcMgr_nPNC19, 31, 31, VfcMgr__vRiPwrSldgDoorBtnDetect }, /*!> RiPwrSldgDoorBtn */{VfcMgr_nVFC21, VfcMgr_nPNC19, 15, 31, VfcMgr__vLockgCtrlForHmiCen_PowerClosuresDetect }, /*!> LockgCtrlForHmiCen_PowerClosures */{VfcMgr_nVFC21, VfcMgr_nPNC19, 15, 31, VfcMgr__vPwrDoorCtrlForHmiCen_PowerClosuresDetect }, /*!> PwrDoorCtrlForHmiCen_PowerClosures */{VfcMgr_nVFC21, VfcMgr_nPNC19, 15, 31, VfcMgr__vActvReSplrForHmiCenDetect }, /*!> ActvReSplrForHmiCen */ };總結(jié)
- 上一篇: React项目实战之租房app项目(十)
- 下一篇: 计算机职称考试internet书籍,全国