2010-01-18 11 views
94

me pasaron un programa legado rubí de larga data, que tiene numerosas apariciones deCaptura Ctrl-C en rubí

begin 
    #dosomething 
rescue Exception => e 
    #halt the exception's progress 
end 

a través de ella.

Sin rastrear cada posible excepción éstas cada uno podría ser la manipulación (por lo menos no inmediatamente), todavía me gustaría ser capaz de apagarlo, a veces con CtrlC.

Y me gustaría hacerlo de una manera que sólo se suma al código (por lo que no afectan el comportamiento existente o se pierda una excepción de lo contrario recogido en el medio de una carrera.)

[CtrlC es SIGINT o SystemExit, que parece ser equivalente a SignalException.new("INT") en el sistema de manejo de excepciones de Ruby. class SignalException < Exception, por lo que este problema se presenta]

El código me gustaría haber escrito sería:.

begin 
    #dosomething 
rescue SignalException => e 
    raise e 
rescue Exception => e 
    #halt the exception's progress 
end 

EDIT: Este código funciona, siempre y cuando se obtiene la clase de la excepción quieres atrapar correctamente Eso es SystemExit, Interrupt o IRB :: Abort como se muestra a continuación.

Respuesta

113

El problema es que cuando un programa Ruby finaliza, lo hace al aumentar SystemExit. Cuando entra un control-C, aumenta Interrumpir. Dado que SystemExit y Interrupt derivan de Excepción, el manejo de su excepción detiene la salida o la interrupción en sus pistas. Aquí está la solución:

Siempre que es posible, cambiar

rescue Exception => e 
    # ... 
end 

a

rescue StandardError => e 
    # ... 
end 

para aquellos que no se puede cambiar a StandardError, re-plantear la excepción:

rescue Exception => e 
    # ... 
    raise 
end 

o, como mínimo, volver a subir el SystemExit e Interrupt

rescue SystemExit, Interrupt 
    raise 
rescue Exception => e 
    #... 
end 

Cualquier excepción personalizados que ha hecho debe derivar de StandardError, no Excepción.

+0

Wayne, ¿sería tan amable de agregar un ejemplo IRB :: Abort a su lista también? –

+1

@Tim, vaya a buscar irb.rb (en mi sistema, está en /usr/lib/ruby/1.8/irb.rb) y encuentre el ciclo principal (busque @ context.evaluate). Mire las cláusulas de rescate y creo que comprenderá por qué IRB se comporta de la manera en que lo hace. –

+0

gracias. Ver la definición de #signal_handle en irb.rb también me ayudó a entenderlo. También tienen un buen truco dentro de la unión de la variable de excepción del bucle principal. (Utilizando las cláusulas de rescate como una forma de seleccionar una excepción específica, luego usando esa excepción fuera de los cuerpos de rescate.) –

63

Si se puede envolver todo el programa que se puede hacer algo como lo siguiente:

trap("SIGINT") { throw :ctrl_c } 

catch :ctrl_c do 
begin 
    sleep(10) 
rescue Exception 
    puts "Not printed" 
end 
end 

Esto básicamente tiene CtrlC uso de captura/tirar en lugar de manejo de excepciones, por lo menos que el código ya existente tiene una trampa: ctrl_c en él, debería estar bien.

Como alternativa, puede hacer un trap("SIGINT") { exit! }. exit! sale inmediatamente, no genera una excepción, por lo que el código no puede atraparlo accidentalmente.

+2

Tenga en cuenta que Ctrl-C en IRB envía IRB :: Abort, no SIGINT. De lo contrario, la respuesta de @ Logan es una solución. –

+1

@TimSnowhite para el intérprete de rubí 'SIGINT' funciona bien para mí. – defhlt

+1

lanzar y atrapar debe estar en el mismo hilo, por lo que esto no funcionará si desea capturar la excepción de Interrupción en otro hilo. –

25

Si no puede envolver toda su aplicación en un bloque begin ... rescue (por ejemplo, Thor) puede simplemente trampa SIGINT:

trap "SIGINT" do 
    puts "Exiting" 
    exit 130 
end 

130 es un código de salida estándar.

+0

FYI, 130 es el código de salida correcto para las secuencias de comandos interrumpidas por Ctrl-C: https://www.google.com/search?q=130+exit+code&en= ('130 | Script terminado por Control-C | Ctl-C | Control-C es la señal de error fatal 2, (130 = 128 + 2, ver arriba) ') – Dorian

3

¡Estoy usando ensure con gran efecto! Esto es para las cosas que quieres que sucedan cuando tus cosas terminan sin importar por qué termina.