zoukankan      html  css  js  c++  java
  • TinyTemplate(Velocity Plus版)即将火热推出

    本来是没有自己写一个模板引擎的计划的,因为按我的理解,一直认识这种“语言”级的引擎,难度是非常大的。总感觉自己的水平不够,因此不敢有这个念头。直到大量使用Velocty的时候,碰到velocty诸多尽如人意的地方,但是又无能为力,退回到JSP吧,又心不有甘。于是就期望着寻找一种语法结构接近velocty,但是又没有Velocity这些不方便之处的模板语言。于是进到一个模板语言群,一群大佬们个个至少是一个模板语言的作者,于是作者在里面表达了自己的期望,大佬们都介绍了自己的模板引擎,于是作者一个接一个的看源码,看文档。说实际,看文档,感觉都非常不错,都有自己的特色,看语法也都不错,除了一部分自己特别关注的点没有之外,其部分都非常不错了。但是距离自己的诉求还是有差距,怎么办呢?于是就准备找一个最接近的模板引擎来进行一定的扩展,挑来挑去就挑中了jetbrick这个模板语言(在此对Jetbrick致以强烈的衷心的感谢!!)。
    之所以挑这个呢,是因为以下几个原因:
    • Antlr语言文件编写非常清晰,对于我这种Antlr盲来说,也可以看得懂,甚至可以照葫芦画瓢修改修改,这个非常重要,在后期作者进行了相当的语法改进,这个方面有极度体现
    • 代码质量较好,使用sonar进行进行分析,给的结果都还是相当不错的,在作者看过的所有的模板语言中,算上成之选
    • 语法结构与Velocity的非常接近,这点对我也非常重要,因为我的想法就是velocity语法有相当的接受度,与Velocity语法接近,velocity的一些使用者可以方便的进行切换
    • 测试用例比较完善,当时也就是这么一看,但是最后Tiny模板引擎完成之后,利用其测试用例进行测试发现了好几个BUG,说明还是非常有效果的

    于是下载了源码,初端详还是不错的,但是在实现在几点和笔记诉求有差距:
    第一我希望是弱类型,jetbrick是强类型,性能是有提高但是开发过程会比较不方便。
    另外由于jetbrick作者期望在编译器进行强类型推测,因此导致运行期的内容与编译期的内容有比较强的耦合。
    另外有一些语言特性,属于个人爱好上的原因,也有一些差异,因此就决定自己编写一个。

    语法规范为了更好的说明Tiny的语法规范,因此全程对比Velocity
    说明,<>中的内容表示必须有至少一个,[]中的内容表示可以有可以没有。References表达式${表达式}
    表达式是指最后的运算结果是一个值,表达式中可以使用变量
    =>与Velocity区别,这里大括号必须有,不能省略,“-”号不允许出现
    ${a+b-c+d}
    ${"abc"+1}
    ${user.name}
    ${user.items[1].count+3}
    ${user.func(1,2,3,4)+map.def+map["aa"]}
    变量
    <a->[_a-zA-z0-9]
    =>与Velocity区别,“-”号不允许出现
    示例:
    合法

    • abc
    • ab_c
    • Ab9_

    非法

    • 9bc
    • _bc
    • a-b

    属性值属性语法与变量名一样
    区别大括号必须有,“-”号不可以有
    属性值实际上也是个表达式,因此这么写也是可以的
    ${a.("aa"+bb)},如果bb的值为3,则等同于${a.aa3},等同于a."aa3"
    指令#set - 赋值指令Format:
    #set ( ref = [ "' ]arg[ "' ] )
    示例
    #{set}不被支持
    变量名前面不可以加$
    #set(aa=1)
    #set(aa=2,b=2,c=aa+2,d=func("info"))
    #set(aa=[aa,"bb",2,3,4]
    #set(aa={"aa":1,bb:2,aa.bb.func()+3:5}
    #if/#elseif/#else - 判断语句格式:
    #if( [condition] ) [output] [ #elseif( [condition] ) [output] ]* [ # [ { ] else [ } ] [output] ] # [ { ] end [ } ]
    用法:
    #if(aa)
    #end
    #if(aa||bb)
    #end
    这里即可以是逻辑表达式,也可以是非逻辑表达式
    情况如下:
    如果是null,则false
    如果是boolean值,看true/false
    如果是String,看长度>0
    如果是Collection,看Size>0
    如果是Iterator看hasNext
    如果是数组,看长度>0
    如果是Enumerator,看hasMoreElements
    如果是Map看size
    其它情况,就返回true
    下面所有的逻辑表达式都支持
    Operator Name   
    Symbol    
    Alternative Symbol    
    Example
    Equals Number   
    ==    
    eq    
    #if( $foo == 42 )
    Equals String   
    ==    
    eq    
    #if( $foo == "bar" )
    Object Equivalence   
    ==    
    eq    
    #if( $foo == $bar )
    Not Equals   
    !=    
    ne    
    #if( $foo != $bar )
    Greater Than   
    >     
    gt    
    #if( $foo > 42 )
    Less Than   
    <     
    lt    
    #if( $foo < 42 )
    Greater Than or Equal To   
    > =    
    ge    
    #if( $foo >= 42 )
    Less Than or Equal To   
    < =    
    le    
    #if( $foo <= 42 )
    Boolean NOT   
    !    
    not    
    #if( !$foo )
    Notes:

    • ==用的是equals
    • 可以用下面的方式来避免与显示内容分不开

    #if(foo == bar)it's true!#{else}it's not!#end</li>
    注意:与Velocity区别:变量名前面不要加“$”符号
    #for - for循环指令Format:
    # for(varName : collection) 显示内容1 [#[{]else[}] ]  显示内容2 # [ { ] end [ } ]
    表示对集合进行循环,执行显示内容1,如果集合为空,则执行显示内容2
    注意:与Velocity区别:增了了#else指令
    可以是collection的内容:
    数组、集合、Iterator,Enumeration,Map,对象,甚至null
    如果不是集合对象,只是一个普通对象,就只循环次,这比较适合于有时候会返回列表,有时候会返回一个对象的情况,就避免了增加复杂的判断。
    #include - 包含指令Format:
    #include(expression[,{aa:1,bb:2}])
    示例:
    #include("/aa/bb/cc.vm")
    #include("/aa/bb/cc.vm")
    与Velocity的区别:用于把另外的页面在当前位置进行渲染,后面只能加一个Map用来传递参数
    #parse:指令已经没有意义被取消#stop - Stops the template engineFormat:
    #stop[(expresson)]
    Usage:
    #if(aa==bb)
    #stop
    #end
    等价于
    #stop(aa==bb)
    #break - Stops the current directiveFormat:
    #break[(expresson)]
    Usage:
    #if(aa==bb)
    #break
    #end
    等价于
    #break(aa==bb)
    #continue[(expresson)]
    Usage:
    #if(aa==bb)
    #continue
    #end
    等价于
    #continue(aa==bb)
    #evaluate - Dynamically evaluates a string or reference由于难用被取消,且用处太小被取消增加指令#[@]call
    #call("aa"+"bb",1,2)
    等同于
    #aabb(1,2)
    #call(format("Sys%sMdl%s",1,2),1,2)
    等同于
    #Sys1Mdl2(1,2)
    #@call("aa"+"bb",1,2)
    ...
    #end
    等同于
    #@aabb(1,2)
    ...
    #end
    #@call(format("Sys%sMdl%s",1,2),1,2)
    ...
    #end
    等同于
    #@Sys1Mdl2(1,2
    ...
    #end
    另外支持命名传递,详见宏调用
    #define - 由于鸡肋被取消,调用者中的所有变量对于被调用者都可见,不再需要显式传递#macro - 定义宏Format:
    # macro macroName( arg1 [, arg2,arg3 ... argn ] ) [ VM VTL code... ] # [ { ] end [ } ]
    与 Velocity不同:macroName由括号里放在了括号外面,避免与参数混一起,参数之间必须用逗号隔开
    调用宏有两种方式
    #vmname( arg1,arg2 )
    #@vmname(arg1,args)
    ....
    #end
    与Velocity不同:支持命名调用:
    比如下面的方式; #vmname(arg2=3),也可以混用:#vmname(1,2,arg5=3,arg4=4)
    注释:
    ##单行注释
    #-- ... --#  #* ... *#,两种格式支持,是考虑到在<!-- -->的时候,改成#-- --#更方便

    非解析标记,下面的内容会原样输出
    #[[
    This has invalid syntax that would normally need "poor man's escaping" like:


      • #define()

    • ${blah

    ]]#

    新增加内容:i18n支持:
    $${aaa.bbb.ccc}

    表示显示aaa.bbb.ccc对应的国际化内容
    当然,还有强大的布局(页面继承),容易的使用(会vm的到现在已经会用),方便的扩展(非常容易扩展),微小的体量(引擎只有2000行代码),还想要什么,可以尽情提出。
    新增内容:Java对象方法扩展,即在不修改原类的情况下,对java类添加
    比如可以为String增加bold函数,通过下面的方式来进行加粗
    ${“悠然是个好同志”.bold()}
    也可以给 Object增加toJson,toXml等方法,从而直接用下面的方式输出json或xml:
    ${user.toJson()},${user.toXml()}
    当然,现在还有一点计划中的特性没有实现,那就是装饰方式的布局方式,可能有些同学不了解,那就先留点悬念吧。

  • 相关阅读:
    【LeetCode-动态规划】编辑距离
    【LeetCode-栈】计算器
    【LeetCode-栈】字符串解码
    【LeetCode-数组】缺失的第一个正数
    【LeetCode-查找】寻找重复数
    【LeetCode-堆】丑数
    【LeetCode-堆】数据流中的第K大元素
    【LeetCode-排序】根据身高重建队列
    立项与启动
    JS中match方法探究
  • 原文地址:https://www.cnblogs.com/j2eetop/p/4609979.html
Copyright © 2011-2022 走看看