在 Groovy 中打印闭包定义/源代码
Posted
技术标签:
【中文标题】在 Groovy 中打印闭包定义/源代码【英文标题】:print the closure definition/source in Groovy 【发布时间】:2011-07-12 21:22:29 【问题描述】:谁知道在 Groovy 中如何打印闭包的来源?
比如我有这个闭包(绑定到a
)
def a = it.twice()
我想要String
"it.twice()" 或 " it.twice() "
只是一个简单的toString
当然是行不通的:
a.toString(); //results in: Script1$_run_closure1_closure4_closure6@12f1bf0
【问题讨论】:
这可能与您的情况不符,但您或许可以另辟蹊径。由于 GroovyShell.evaluate() 执行一个字符串(带有适当的 var 绑定),如果闭包只是一个字符串呢? 【参考方案1】:简短的回答是你不能。长答案是: 根据您需要代码的目的,您也许可以逃脱
// file: example1.groovy
def a = it.twice()
println a.metaClass.classNode.getDeclaredMethods("doCall")[0].code.text
// prints: return it.twice()
但是 您将需要在类路径 AT RUNTIME 中可用的脚本源代码,如
中所述groovy.lang.MetaClass#getClassNode() "获取对原始的引用 MetaClass 的 AST(如果是) 在运行时可用 @return 原始 AST 或 null 如果不能 归还”
与text 技巧并没有真正返回相同的代码,只是一个类似于 AST 表示的代码,正如可以在这个脚本中看到的那样
// file: example2.groovy
def b = p-> p.twice() * "p"
println b.metaClass.classNode.getDeclaredMethods("doCall")[0].code.text
// prints: return (p.twice() * p)
不过,如果您只是想快速浏览一下,它可能会很有用
而且,如果您手头有太多时间并且不知道该做什么,您可以编写自己的org.codehaus.groovy.ast.GroovyCodeVisitor
来漂亮地打印它
或者,偷一个现有的,比如groovy.inspect.swingui.AstNodeToScriptVisitor
// file: example3.groovy
def c = w->
[1,2,3].each
println "$it"
(1..it).each x->
println 'this seems' << ' somewhat closer' << ''' to the
original''' << " $x"
def node = c.metaClass.classNode.getDeclaredMethods("doCall")[0].code
def writer = new StringWriter()
node.visit new groovy.inspect.swingui.AstNodeToScriptVisitor(writer)
println writer
// prints: return [1, 2, 3].each(
// this.println("$it")
// return (1.. it ).each( java.lang.Object x ->
// return this.println('this seems' << ' somewhat closer' << ' to the \n original' << " $x")
// )
// )
现在。 如果您想要原始、准确、可运行的代码......那你就走运了 我的意思是,您可以使用源代码行信息,但上次我检查时,并没有真正让它们正确
// file: example1.groovy
....
def code = a.metaClass.classNode.getDeclaredMethods("doCall")[0].code
println "$code.lineNumber $code.columnNumber $code.lastLineNumber $code.lastColumnNumber"
new File('example1.groovy').readLines()
... etc etc you get the idea.
行号应该至少接近原始代码
【讨论】:
我不明白“运行时类路径中可用的脚本”到底是什么意思?它还不能工作(ClassNode 是null
),但我有所有可用的资源。是否必须在 Groovy 项目的类路径中添加脚本的位置?
@Julian 表示 .groovy 文件应该在类路径中。 getClassNode() 基本上会加载文件,然后用一个特殊的钩子再次编译它以保存相关的 ast 节点,并返回它
@jpertino 关于如何在 Grails 环境中执行此操作有什么想法吗?我有一个 Config.groovy 文件,它在集成测试期间位于类路径上,但在运行应用程序期间却没有。
与 Jenkins 无关 - 只是说就我而言,我无法让它在那里工作 - 可能这些类在 jenkins slave 运行时中不可用。【参考方案2】:
这在 groovy 中是不可能的。即使直接运行 groovy 脚本,无需先编译,脚本也会被转换为 JVM 字节码。闭包没有任何不同的处理方式,它们像常规方法一样编译。到代码运行时,源代码不再可用。
【讨论】:
以上是关于在 Groovy 中打印闭包定义/源代码的主要内容,如果未能解决你的问题,请参考以下文章
Groovy闭包 Closure ( 闭包调用 | 闭包默认参数 it | 代码示例 )
Groovy闭包 Closure ( 闭包调用 与 call 方法关联 | 接口中定义 call() 方法 | 类中定义 call() 方法 | 代码示例 )
Groovy闭包 Closure ( 闭包调用 与 call 方法关联 | 接口中定义 call() 方法 | 类中定义 call() 方法 | 代码示例 )
Groovy闭包 Closure ( 闭包定义 | 闭包类型 | 查看编译后的字节码文件中的闭包类型变量 )