распечатать определение замыкания / источник в Groovy - PullRequest
14 голосов
/ 10 марта 2011

Кто-нибудь знает, как печатать источник замыкания в Groovy?

Например, у меня есть это закрытие (привязано к a)

def a = { it.twice() } 

Я хотел бы иметь String "it.twice ()" или "{it.twice ()}"

Просто простой toString курс не сработает:

a.toString(); //results in: Script1$_run_closure1_closure4_closure6@12f1bf0

Ответы [ 2 ]

28 голосов
/ 12 марта 2011

короткий ответ: ты не можешь.длинный ответ:
в зависимости от того, для чего вам нужен код, вы, возможно, можете обойтись без

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

НО
вам понадобится исходный код скрипта, доступный в classpath AT RUNTIMEкак объяснено в

groovy.lang.MetaClass # getClassNode ()
"Получает ссылку на исходный AST для MetaClass, если он доступен во время выполнения
@return Исходный AST илиnull, если он не может быть возвращен "

AND
трюк 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")
//     })
// })

сейчас.
если выхотите оригинал , точный, работоспособный код ... вас нетuck
я имею в виду, вы можете использовать информацию об исходных строках, но в прошлый раз, когда я проверял, они не совсем правильно поняли

// 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.  

номера строк должны хотя бы соответствовать исходному коду

6 голосов
/ 10 марта 2011

Это не возможно в заводной.Даже если Groovy-скрипт запускается напрямую, без предварительной компиляции, он преобразуется в байт-код JVM.Замыкания не обрабатываются иначе, они компилируются как обычные методы.Ко времени выполнения кода исходный код больше не доступен.

...