Распечатать определение замыкания / источник в Groovy
Кто-нибудь знает, как печатать источник замыкания в Groovy?
Например, у меня есть это закрытие (привязано к a
)
def a = { it.twice() }
Я хотел бы иметь String
"it.twice()" или "{ it.twice() }"
Просто простой toString
конечно не сработает
a.toString(); //results in: Script1$_run_closure1_closure4_closure6@12f1bf0
2 ответа
Короткий ответ: ты не можешь. длинный ответ:
в зависимости от того, для чего вам нужен код, вы можете сойти с рук
// file: example1.groovy
def a = { it.twice() }
println a.metaClass.classNode.getDeclaredMethods("doCall")[0].code.text
// prints: { return it.twice() }
НО
вам понадобится исходный код скрипта, доступный в пути к классам в режиме RUNTIME, как описано в
groovy.lang.MetaClass # getClassNode ()
"Получает ссылку на исходный AST для MetaClass, если он доступен во время выполнения
@return Исходный AST или ноль, если он не может быть возвращен "
А ТАКЖЕ
текстовый трюк на самом деле не возвращает тот же код, просто код, похожий на представление 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.
Номера строк должны быть хотя бы рядом с исходным кодом
Это не возможно в заводной. Даже когда Groovy-скрипт запускается напрямую, без предварительной компиляции, он преобразуется в байт-код JVM. Замыкания не обрабатываются иначе, они компилируются как обычные методы. К тому времени, когда код выполняется, исходный код больше не доступен.