在Groovy中打印闭包定义/源代码

Jul*_*ian 15 groovy closures

谁知道如何在Groovy中打印封闭源?

例如,我有这个闭包(绑定到a)

def a = { it.twice() } 
Run Code Online (Sandbox Code Playgroud)

我想要String "it.twice()"或"{it.twice()}"

只是一个简单的过程是toString行不通的:

a.toString(); //results in: Script1$_run_closure1_closure4_closure6@12f1bf0
Run Code Online (Sandbox Code Playgroud)

小智 28

简短的回答是你不能.答案很长:
取决于你需要的代码,你也许可以逃脱

// file: example1.groovy
def a = { it.twice() }
println a.metaClass.classNode.getDeclaredMethods("doCall")[0].code.text
// prints: { return it.twice() }
Run Code Online (Sandbox Code Playgroud)

但是
你将需要类路径AT RUNTIME中提供的脚本的源代码,如中所述

groovy.lang.MetaClass #getClassNode()
"如果MetaClass在运行时可用,则获得对原始AST的引用
@return原始AST,如果无法返回,则返回null"


文字把戏并没有真正返回相同的代码,就像AST的表示的代码,可以在该脚本中可以看出

// file: example2.groovy
def b = {p-> p.twice() * "p"}
println b.metaClass.classNode.getDeclaredMethods("doCall")[0].code.text
// prints: { return (p.twice() * p) }
Run Code Online (Sandbox Code Playgroud)

如果你只是想快速浏览一下,它可能会很有用

并且,如果你手上有太多时间而不知道该怎么做,你可以自己编写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")
//     })
// })
Run Code Online (Sandbox Code Playgroud)

现在.
如果你想要原始的,准确的,可运行的代码......你运气不好
我的意思是,你可以使用源代码行信息,但是上次我检查时,它并没有真正让他们正确

// 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.  
Run Code Online (Sandbox Code Playgroud)

尽管如此,行号仍然至少接近原始代码

  • @jpertino有关如何在Grails环境中执行此操作的任何想法?我有一个Config.groovy文件,它在集成测试期间在类路径上,但它不是在run-app期间. (2认同)

ata*_*lor 6

这在groovy中是不可能的.即使直接运行groovy脚本而不先编译它,脚本也会转换为JVM字节码.闭包不会有任何不同的处理,它们像常规方法一样编译.到运行代码时,源代码不再可用.