2012-02-23 14 views
6

Es posible obtener el número de línea actual por __LINE__ en Ruby o Perl. Por ejemplo:__LINE__ función en Groovy

print "filename: #{__FILE__}, line: #{__LINE__}" 

¿Existe la misma característica en Groovy?

Respuesta

2

No directamente, pero puede obtenerlo a través de un rastro de pila de Excepción (o Arrojable). Por ejemplo:

StackTraceElement getStackFrame(String debugMethodName) { 
    def ignorePackages = [ 
     'sun.', 
     'java.lang', 
     'org.codehaus', 
     'groovy.lang' 
    ] 
    StackTraceElement frame = null 
    Throwable t = new Throwable() 
    t.stackTrace.eachWithIndex { StackTraceElement stElement, int index -> 
     if (stElement.methodName.contains(debugMethodName)) { 
      int callerIndex = index + 1 
      while (t.stackTrace[callerIndex].isNativeMethod() || 
        ignorePackages.any { String packageName -> 
         t.stackTrace[callerIndex].className.startsWith(packageName) 
        }) { 
       callerIndex++ 
      } 
      frame = t.stackTrace[callerIndex] 
      return 
     } 
    } 
    frame 
} 

int getLineNumber() { 
    getStackFrame('getLineNumber')?.lineNumber ?: -1 
} 

String getFileName() { 
    getStackFrame('getFileName')?.fileName 
} 

String getMethodName() { 
    getStackFrame('getMethodName')?.methodName 
} 

def foo() { 
    println "looking at $fileName:$lineNumber ($methodName)" 
} 

foo() 

// ==> looking at test.groovy:39 (foo) 

Una palabra de precaución sin embargo: obtener el número de línea, nombre de archivo o método como este es muy lento.

+0

¿Por qué es tan lento? El equivalente en Perl (es decir, a través de 'calller') es muy rápido. – tchrist

+0

Los rastros de pila de Java pueden ser bastante profundos, incluso más increíbles. El método [Throwable.fillInStackTrace] (http://docs.oracle.com/javase/6/docs/api/java/lang/Throwable.html#fillInStackTrace%28%29) solo lleva un tiempo para generar los datos de seguimiento de pila estructura. Visite http://stackoverflow.com/a/3980148/190201 para una mirada más profunda. Ciertamente no es demasiado lento de usar para la depuración, pero es bueno conocer su costo antes de usarlo. – ataylor

1

No soy un experto en Groovy, pero no lo creo. Sé que Java y C# no lo tienen.

La característica __LINE__ realmente comenzó a ayudar con la depuración en C. C no tiene excepciones ni muchas de las otras características que tienen los lenguajes modernos, pero sí tenía macros que el compilador podía expandir a cualquier parte del código, razón por la cual necesitábamos __FILE__, __LINE__, etc. para hacernos saber dónde estábamos cuando sucedía algo malo. Así es como funciona assert en C y C++. La JVM tiene muy buenas herramientas de depuración, y combinadas con assert y excepciones, puedes identificar fácilmente dónde algo salió mal (los rastreos de pila son mucho mejores que solo un número de línea).

Creo que la razón por la que Ruby y Perl tienen esas macros es porque fueron creadas por hackers de C. Nunca utilicé ninguno de esos lenguajes para conocer el nivel de soporte de depuración o qué tan útiles son realmente las macros.

+0

Puedo confirmar que no se usan mucho. La forma normal de obtener información sobre un marco en Perl, ya sea dentro del depurador o fuera de él, es usar la función 'llamante' con un número de cuadro como argumento. 0 es donde estás ahora, 1 es tu interlocutor, 2 es * su * persona que llama, etc. Esto ahora devuelve el paquete, el nombre de archivo, la línea, la subrutina y un montón de otras cosas del marco. Por lo tanto, normalmente usaría la interfaz funcional para obtener esa información, no las antiguas pseudo-macros '__FILE__' y' __LINE__'. – tchrist