在Velocity模板宏中关闭 [英] Closure in Velocity template macros

查看:220
本文介绍了在Velocity模板宏中关闭的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个几个Velocity宏,像这样:

  #macro(Alpha)
#set $ p = 1)
#@ Beta()
$ p // 1
$ bodyContent
#end
#end

#宏(Beta $ params)
#set($ p = 2)
$ p // 2
$ bodyContent
#end



我使用它们:

  #set($ p = 0)
#@ Alpha(...)
$ p // 3
#end

我相信这会呈现如下(忽略格式化):2,2,2



喜欢有合适的关闭行为,包括隐藏父作用域名称的更多局部范围的名称。特别地,标记为3的$ p的使用应该指向值0,2指向值2,而指向1指向值1.



给定正确的闭包语义,它将打印:2,1,0



有任何方法来获得这个,或者实现一个自定义指令/修改#macro指令行为来实现这一点?

解决方案

Velocity是一个模板引擎,不是一个合适的编程语言,如何工作。



宏不是Java或C中的函数,意味着调用宏不会在局部变量的堆栈上创建一个新的段;速度适用于上下文,大多数时候只有一个全局上下文。



仍然有两种方法处理局部变量:


  1. velocimacro.context.localscope 配置参数,阻止在宏内更改全局变量;请注意,此设置已弃用,将在Velocity 2.0中删除

  2. 您可以使用 $ macro 变量作为私有如果您启用 macro.provide.scope.control 配置参数

仍然有另一个问题,会阻止您的代码正常运行: Velocity宏主要作为宏调用扩展,这意味着传递给宏的主体不会先计算,然后传递给宏;当嵌套宏被执行时,它将被动态地评估。代码行为如下:

  #macro(Alpha)
#set($ macro.p = 1) - > ; $ macro是指Alpha
$ p - > $ p将始终为0,因为我们正在更改一个局部变量
$ macro.p - > 1 here
$ bodyContent - >这里使用$ p,并且打印0。
#@ Beta()
$ macro.p - >它现在是1,但是当这行将被实际评估时,$ macro将引用Beta,因此2将被打印
$ bodyContent - >它是Beta宏的内容,触发无限递归;它不是$ p如上
#end
#end

#macro(Beta)
#set($ macro.p = 2) - > $ macro是指Beta
$ macro.p - > 2 here
$ bodyContent - >传递给$ bodyContent的$ bodyContent现在被评估,所以它导致递归
#end

#set($ p = 0)
#@ Alpha()
$ p - >全局变量
#end


I've got a couple Velocity macros like this:

#macro(Alpha)
  #set($p = 1)
  #@Beta()
    $p             // 1
    $bodyContent
  #end
#end

#macro(Beta $params)
  #set($p = 2)
  $p               // 2
  $bodyContent
#end

And I'm using them like so:

#set($p = 0)
#@Alpha(...)
  $p               // 3
#end

I believe this renders like so (ignore formatting): 2, 2, 2

But I'd like to have proper closure behavior, including more locally scoped names hiding parent scope names. In particular, the usage of $p labelled '3' should refer to the value 0, '2' to the value 2, and '1' to the value 1.

Given proper closure semantics, it would print: 2, 1, 0

Is there any way to get this, or a way to implement a custom directive / modify #macro directive behavior to achieve this?

解决方案

Velocity is a templating engine, not a proper programming language, so it's a bit harder to grasp how it works.

Macros are not functions like in Java or C, meaning that invoking a macro isn't going to create a new segment on the stack for local variables; velocity works with a context, and most of the time there's just one global context.

Still, there are two ways of dealing with local variables:

  1. There's the velocimacro.context.localscope configuration parameter that prevents changing global variables from within macros; note that this setting is deprecated and will be removed in Velocity 2.0
  2. You can use the $macro variable as a local container for private variables if you enable the macro.provide.scope.control configuration parameter

Still, there's another problem that would prevent your code from running correctly: Velocity macros work mostly as call-by-macro expansion, which means that the body passed to a macro isn't evaluated first, then passed to the macro; it will be evaluated dynamically when the nested macro is executed. The code behaves as:

#macro(Alpha)
  #set($macro.p = 1)  -> $macro refers to Alpha
  $p -> $p will always be 0, since we're changing a local variable
  $macro.p  -> 1 here
  $bodyContent  -> Here $p is used, and 0 is printed
  #@Beta()
    $macro.p  -> it is 1 now, but when this line will be actually evaluated, $macro will refer to Beta, so 2 will be printed
    $bodyContent  -> It's the content of the Beta macro, which triggers an infinite recursion; it's not $p as above
  #end
#end

#macro(Beta)
  #set($macro.p = 2)  -> $macro refers to Beta
  $macro.p  -> 2 here
  $bodyContent  -> the $bodyContent that was passed into the $bodyContent is evaluated now, so it causes a recursion
#end

#set($p = 0)
#@Alpha()
  $p  -> Global variable
#end

这篇关于在Velocity模板宏中关闭的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆