with try standard rails pages exceptions error catch ruby-on-rails ruby exception exception-handling error-handling

ruby-on-rails - try - ruby standard error



¿Comenzar, rescatar y asegurar en Ruby? (7)

Para su información, incluso si se vuelve a elevar una excepción en la sección de rescue , el bloque de garantía se ejecutará antes de que la ejecución del código continúe en el siguiente controlador de excepciones. Por ejemplo:

begin raise "Error!!" rescue puts "test1" raise # Reraise exception ensure puts "Ensure block" end

Recientemente empecé a programar en Ruby, y estoy mirando el manejo de excepciones.

Me preguntaba si la ensure era el equivalente de Ruby finally en C #. Debería tener:

file = File.open("myFile.txt", "w") begin file << "#{content} /n" rescue #handle the error here ensure file.close unless file.nil? end

o debo hacer esto?

#store the file file = File.open("myFile.txt", "w") begin file << "#{content} /n" file.close rescue #handle the error here ensure file.close unless file.nil? end

¿ ensure se llame sin importar qué, incluso si no se produce una excepción?


Por eso necesitamos ensure :

def hoge begin raise rescue raise # raise again ensure puts ''ensure'' # will be executed end puts ''end of func'' # never be executed end


Sí, ensure ENSURES se ejecute cada vez, para que no necesite el file.close en el bloque de begin .

Por cierto, una buena manera de probar es hacer:

begin # Raise an error here raise "Error!!" rescue #handle the error here ensure p "=========inside ensure block" end

Puede realizar una prueba para ver si se imprime "========= dentro del bloque de garantía" cuando haya una excepción. Luego puede comentar la declaración que genera el error y ver si la declaración de garantía se ejecuta al ver si algo se imprime.


Sí, ensure que finally garantiza que el bloque será ejecutado . Esto es muy útil para asegurarse de que los recursos críticos estén protegidos, por ejemplo, cerrar un identificador de archivo en caso de error o liberar un mutex.


Sí, ensure que el código siempre sea evaluado. Por eso se llama ensure . Entonces, es equivalente a Java y C # finally .

El flujo general de begin / rescue / else / ensure / end ve así:

begin # something which might raise an exception rescue SomeExceptionClass => some_variable # code that deals with some exception rescue SomeOtherException => some_other_variable # code that deals with some other exception else # code that runs only if *no* exception was raised ensure # ensure that this code always runs, no matter what # does not change the final value of the block end

Usted puede dejar de rescue , ensure o de lo else . También puede omitir las variables, en cuyo caso no podrá inspeccionar la excepción en su código de manejo de excepciones. (Bueno, siempre puede usar la variable de excepción global para acceder a la última excepción que se generó, pero eso es un poco intrépido). Y puede omitir la clase de excepción, en cuyo caso se capturarán todas las excepciones heredadas de StandardError . (Tenga en cuenta que esto no significa que se capturen todas las excepciones, porque hay excepciones que son instancias de Exception pero StandardError . Principalmente, excepciones muy severas que comprometen la integridad del programa, como SystemStackError , NoMemoryError , SecurityError , NotImplementedError , LoadError , SyntaxError , ScriptError , Interrupt , SignalException o SystemExit .)

Algunos bloques forman bloques de excepción implícitos. Por ejemplo, las definiciones de métodos son también implícitamente bloques de excepción, así que en lugar de escribir

def foo begin # ... rescue # ... end end

tu solo escribes

def foo # ... rescue # ... end

o

def foo # ... ensure # ... end

Lo mismo se aplica a class definiciones de class y las definiciones de module .

Sin embargo, en el caso específico sobre el que estás preguntando, hay un idioma mucho mejor. En general, cuando trabaja con algún recurso que necesita limpiar al final, lo hace pasando un bloque a un método que hace toda la limpieza por usted. Es similar a un bloque de using en C #, excepto que Ruby es lo suficientemente poderoso como para que no tengas que esperar a que los sumos sacerdotes de Microsoft bajen de la montaña y cambien amablemente su compilador. En Ruby, puedes implementarlo tú mismo:

# This is what you want to do: File.open(''myFile.txt'', ''w'') do |file| file.puts content end # And this is how you might implement it: def File.open(filename, mode=''r'', perm=nil, opt=nil) yield filehandle = new(filename, mode, perm, opt) ensure filehandle&.close end

Y qué sabe: esto ya está disponible en la biblioteca central como File.open . Pero es un patrón general que también puede usar en su propio código, para implementar cualquier tipo de limpieza de recursos (a la using en C #) o transacciones o cualquier otra cosa que pueda pensar.

El único caso donde esto no funciona, si la adquisición y la liberación del recurso se distribuyen en diferentes partes del programa. Pero si está localizado, como en su ejemplo, entonces puede usar fácilmente estos bloques de recursos.

Por cierto: en C # moderno, el using es realmente superfluo, porque puedes implementar tú mismo los bloques de recursos de estilo Ruby:

class File { static T open<T>(string filename, string mode, Func<File, T> block) { var handle = new File(filename, mode); try { return block(handle); } finally { handle.Dispose(); } } } // Usage: File.open("myFile.txt", "w", (file) => { file.WriteLine(contents); });


Sí, ensure se llama en cualquier circunstancia. Para obtener más información, consulte " Excepciones, captura y lanzamiento " del libro de programación de Ruby y busque "asegurar".


Si desea asegurarse de que un archivo está cerrado, debe usar la forma de bloque de File.open :

File.open("myFile.txt", "w") do |file| begin file << "#{content} /n" rescue #handle the error here end end