2011-03-10 11 views
13

Ktoś, kto wie, jak wydruk jest źródłem zamknięcia w Groovy?wydrukuj definicję/źródło zamknięcia w Groovy

Na przykład, ma to zamknięcie (binded do a)

def a = { it.twice() } 

chciałbym mieć String "it.twice()", lub "it.twice {()}"

Wystarczy prosty toString oczywiście nie zadziała:

a.toString(); //results in: [email protected] 
+0

To prawdopodobnie nie będzie pasował do Twojego okoliczności, ale może być w stanie iść w drugą stronę. Od GroovyShell.evaluate() wykonuje String (z odpowiednimi powiązaniami var), co jeśli zamknięcie było po prostu ciągiem znaków? –

Odpowiedz

24

krótka odpowiedź brzmi: nie możesz. długie odpowiedź brzmi:
w zależności od tego, co trzeba kod, można być może uciec z

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

BUT
trzeba będzie kod źródłowy skryptu dostępnego w ścieżce klasy w czasie wykonywania, jak wyjaśniono w

groovy.lang.MetaClass # getClassNode()
„Pobiera odwołanie do oryginalnego AST dla metaklasą jeśli jest dostępny w czasie wykonywania
@return The oryginalnym AST lub null, jeśli nie może być powrócił”

I
się tekstu trik naprawdę nie zwracają ten sam kod, tylko jak kod reprezentacji AST, jak może być widział w tym skrypcie

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

nadal, może to być przydatne, jak to jest, jeśli chcesz po prostu wziąć szybki rzut oka

, a jeśli mają zbyt wiele czasu na swoje ręce i nie wiedzą, co zrobić można napisać własną org.codehaus.groovy.ast.GroovyCodeVisitor do całkiem wydrukować to

OR, tylko ukraść istniejący jak 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") 
//  }) 
// }) 

teraz.
jeśli chcesz oryginalny, dokładny, runnable Kodeksu ... jesteś pecha
To znaczy, można użyć wiersza źródło informacji, ale ostatni raz sprawdzałem, to nie było naprawdę zachęcając prawo

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

numery linii shuld być przynajmniej blisko oryginalnego kodu chociaż

+0

Nie rozumiem, co dokładnie oznacza "skrypt dostępny w ścieżce klas AT RUNTIME"? To nie działa jeszcze (ClassNode ma wartość 'null'), ale mam wszystkie dostępne źródła. Czy muszę dodać lokalizację skryptu w ścieżce klas projektu Groovy? – Julian

+1

@Julian oznacza, że ​​plik .groovy powinien znajdować się w ścieżce klas. the getClassNode() w zasadzie załaduje plik i skompiluje go ponownie za pomocą specjalnego haka, aby zapisać odpowiedni węzeł ast i zwróci go – jpertino

+2

@jpertino Jakieś przemyślenia na temat tego, w jaki sposób zrobiłbyś to w środowisku Grails? Mam plik Config.groovy znajdujący się na ścieżce klasy podczas testów integracji, ale nie jest on podczas uruchamiania aplikacji. – asinesio

5

nie jest to możliwe w Groovy. Nawet jeśli skrypt jest uruchamiany bezpośrednio, bez wcześniejszej kompilacji, skrypt jest konwertowany na kod bajtowy JVM. Zamknięcia nie są traktowane inaczej, są kompilowane jak zwykłe metody. Do czasu uruchomienia kodu kod źródłowy nie będzie już dostępny.