gpt4 book ai didi

scope - Velocity:是否可以嵌套使用 #@ 和 $bodyContent 的宏?

转载 作者:行者123 更新时间:2023-12-04 11:43:19 24 4
gpt4 key购买 nike

我有一个基本上是这样的宏:

#macro( surround $x )
surround:$x
$bodyContent
/surround:$x
#end

调用 #@surround("A")bunch o' stuff#end产生“环绕:一堆东西/环绕:A”作为
预期的。调用 #@surround("A")#@surround("B")more stuff#end#end产生
环绕:A 环绕:B 更多的东西/surround:B/surround:A 这正是我想要的。

但现在我想用另一个宏向上构建
#macro( annotated-surround $x $y )
#@surround( $x )
annotate:$y
$bodyContent
#end
#end
#annotated-surround( "C" "note" ) stuff #end 的预期扩展是
环绕:C 注释:注意的东西/环绕:C

...但这不起作用;我得到了带注释的环绕体的可怕的半无限扩展
内容。

我已阅读 Closure in Velocity template macros 处的答案仍然不太清楚我想做的事情是否可行。

我愿意在 #surround 的定义范围内做任意棘手的事情和 #annotated-surround ,但我不希望这些宏的用户看到任何复杂性。这
整个想法是简化他们的生活。

只要我有你的耳朵:设置 macro.provide.scope.control=true应该是“宏中的本地命名空间”。这是什么意思?提供的命名空间是否独立于默认上下文,但在所有宏的所有调用之间共享一个这样的空间?还是为每个宏调用提供了单独的上下文,甚至是递归的?必须是后者,因为 $macro.parent , 对?

还有一个问题。考虑以下宏:
#macro( recursive $x )
#if($x == 0)
zero
#else
$x before . . .
#set($xMinusOne = $x - 1)
#recursive($xMinusOne)
. . . $x after
#end
#end
#recursive( 4 )产量:

4 之前。 . .
3 之前。 . .
2 之前。 . .
1 之前。 . .
零 。 . .
0 之后。 . .
0 之后。 . .
0 之后。 . .
4 后

现在我明白了所有出现的“0”:只有一个全局 $x,所以分配给它
递归调用粉碎它,它不会得到恢复。但是最后的“4”到底在哪里
来自?就此而言,我的第一个“环绕”宏是如何工作到任意深度的?
为什么它的最终 $x 不会在内部调用中被粉碎?

很抱歉这么冗长,但我一直无法找到有关此事的明确文档。

最佳答案

问题在于全局变量、名称冲突和延迟渲染的组合。

让我们来看看 #@annotated-surround( "x" "y" )content#end 的渲染过程:

  • 渲染进入annotated-surround宏。上下文映射包含:
  • $x = 字符串 x
  • $y = 字符串 y
  • $bodyContent = 可渲染 content - 请注意,尚未评估此字符串的输出。
  • 第一行的渲染进入surround宏。这将上下文映射更新为:
  • 新品 $x = 旧 $x = 字符串 x
  • $y = 字符串 y
  • $bodyContent = 可渲染 annotate:$y\n$bodyContent - 请注意,this 的 String 输出还没有被评估,它仍然是模板代码。
  • 渲染输出surround的第一行,产生字符串 surround:x .
  • 渲染开始评估 surround 的第二行,其中引用了 $bodyContent .
  • 渲染 $bodyContent 的第一行产生字符串 annotate:y .
  • 渲染开始评估 $bodyContent 的第二行,其中引用了 $bodyContent .
  • 渲染 $bodyContent 的第一行产生字符串 annotate:y .
  • 渲染开始评估 $bodyContent 的第二行,其中引用了 $bodyContent .

  • 解决办法是去掉部分问题的组合。全局变量和延迟渲染是 Velocity 工作原理的基本部分,因此您无法触及它们。这留下了名称冲突。您需要的是每个宏的 $bodyContent以不同的名称来引用。这可以通过在调用任何其他宏之前将其分配给每个宏中具有唯一名称的新变量并在任何被调用宏的主体中使用新变量来轻松实现,如下所示:
    #macro( surround $x )
    surround:$x
    $bodyContent
    /surround:$x
    #end

    #macro( annotated-surround $x $y )
    #set( $annotated-surround-content = $bodyContent )
    #@surround( $x )
    annotate:$y
    $annotated-surround-content
    #end
    #end

    这个版本的渲染是这样的:
  • 渲染进入annotated-surround宏。上下文映射包含:
  • $x = 字符串 x
  • $y = 字符串 y
  • $bodyContent = 可渲染 content - 请注意,尚未评估此字符串的输出。
  • 第一行的渲染执行 #set指令,向上下文映射添加一个变量:$annotated-surround-content = 当前 $bodyContent = 可渲染 content .
  • 第二行的渲染进入surround宏。这将上下文映射更新为:
  • 新品 $x = 旧 $x = 字符串 x
  • $y = 字符串 y
  • $annotated-surround-content = 旧 $bodyContent = 可渲染 content
  • $bodyContent = 可渲染 annotate:$y\n$annotated-surround-content
  • 渲染输出surround的第一行,产生字符串 surround:x .
  • 渲染开始评估 surround 的第二行,其中引用了 $bodyContent .
  • 渲染 $bodyContent 的第一行产生字符串 annotate:y .
  • 渲染开始评估 $bodyContent 的第二行,其中引用了 $annotated-surround-content .
  • 渲染$annotated-surround-content产生字符串 content .
  • 渲染输出surround的第三行,产生字符串 /surround:x .

  • 最终渲染输出为 surround:x annotate:y content /surround:x .这种方法可以通过将此类替换应用于所有出现的 $bodyContent 来推广。位于另一个宏调用的内容中,每次使用从宏名称派生的变量名称以确保唯一性。但是,如果没有额外的东西来区分每个嵌套调用,它不适用于递归宏。

    关于范围设置,所做的只是添加 $macro对象到上下文,它对于每个宏调用都是唯一的,可以用作映射。如果您设置 $macro.myVar对于两个嵌套宏调用中的每一个中的不同内容,当内部宏调用完成时,外部宏的值将保持不变。这对 $bodyContent 没有帮助然而,问题是因为对 $macro 的任何引用在宏的内部 $bodyContent渲染时将解析为最里面的宏。

    关于来自 #recursive( 4 ) 的最后 4 个,它来自具有局部作用域并按名称传递的宏参数的组合。对于除 #recursive 的最外层调用之外的所有调用, 参数 $x是对全局上下文变量 $xMinusOne 的引用- 当他们渲染 after线,使用 $x实际上解析为查找 $xMinusOne 的当前值在全局范围内。对于最外层的调用,它是常量值 4 ,并且内部调用的参数在完成时超出范围,所以当最外面的一个到达最后一行时,它又回到了 4 .

    关于scope - Velocity:是否可以嵌套使用 #@ 和 $bodyContent 的宏?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12977064/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com