How to catch all exceptions as soon as they occur by just one rescue statement - ruby

I know how to catch the exceptions but what we do is to put "rescue" after a suspicious section of a code. what if you had a lot functions sending a query to mysql through mysql2 gem and you want to catch their exceptions. One thing you can do is to put a "rescue" statement in each of them. but i want to do that just by one rescue statement. So I put a "rescue" in end of code and put all of code in a "begin" and "end" but it didn't work.
Here is my code and as you see there is a problem in mysql query and just because of "rescue" being end of file, it doesn't catch the exception but when I put it after that query it works.
require 'mysql2'
require 'colored'
begin
def log(string)
p "["+string.cyan+"]"
end
def err
p "["+"FAIL".red+"]"
end
def done
p "["+"DONE".red+"]"
end
class SqlClient
def initialize()
log "SqlClient/initialize"
puts "Host: \n"
#host = gets.strip
puts "User: \n"
#user = gets.strip
puts "Pass: \n"
#pass = gets.strip
#client = Mysql2::Client.new(host: #host , username: #user , password: #pass)
end
def list_databases()
puts "We are listing your databases(not just projects) \n \n \n "
#client.query("ELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA").each do |row|
p row["SCHEMA_NAME"]
end
puts "\n \n \n"
end
end
rescue Mysql2::Error
err
abort
end
`query': You have an error in your SQL syntax; check the manual that corresponds to your
MySQL server version for the right syntax to use near 'ELECT SCHEMA_NAME FROM
INFORMATION_SCHEMA.SCHEMATA' at line 1 (Mysql2::Error)
I'm not looking for something like:
begin
# my code
rescue # this line is right after the code which is going to have problem and we catch it.
end
I'm looking for something like this:
begin
# first method
# second method
# thrid method
# rest of code and etc ...
# now this is end of file:
rescue
end
but as you saw in my code, it didn't work.
UPDATE: I found a similar question here and it seems there will be no answer :| maybe this is a sort of ruby Weakness.

if you want to see ANY error just use e for example
begin
# your call to a method of Mysql2 gem. for example:
client = Mysql2::Client.new(:host => "localhost", :username => "root", etc...)
rescue => e
puts e.message
puts e.backtrace.inspect
end
In order to catch every exception you'd need to wrap each method call with a begin rescue end. When an exception is raised it bails out of the execution so it wouldn't hit the next methods.
To catch all errors I guess I'd do something like this. Keep in mind, this is ugly and I'd recommend for you NOT to do this, but... if you want to try, maybe try something like this:
all_errors = []
# first method you call
begin
# some error might happen here
first_response = Mysql2::Client.new(:host => "localhost", :username => "root", etc...)
rescue => e
all_errors << e
end
# second method you call
begin
# some error might happen here
second_response = Mysql2::Client.new(:host => "localhost", :username => "root", etc...)
rescue => e
all_errors << e
end
puts all_errors.inspect
After a quick search I've found: (http://coderrr.wordpress.com/2008/11/07/the-simple-way-to-print-exceptions-in-ruby/)
# catch all exceptions (anything that derives from Exception)
begin
...
rescue Exception
puts $!, $#
end

You could use an at_exit handler, which has access to the last exception in $!
like
at_exit {
puts "the exception that killed us is", $!
}
If you want to catch Exceptions "as soon as they occur" (not after they're caught) you could use ruby's "debug mode" (which outputs messages when they occur to the console) or ruby-debug see Is there any way to start the Ruby debugger on exception?

Just wrap all your code in:
begin
#yourcode
#as much as you want
rescue
end

Nobody seemed to notice it but using rescue without a class will catch all StandardError and there are so much more.
If you want to catch ALL exceptions you need to do
begin
# your code where you call SqlClient.new etc
rescue Exception => e
puts "error raised"
puts [e, e.backtrace].flatten.join("\n")
end
List of all error classes:
Exception
NoMemoryError
ScriptError
LoadError
NotImplementedError
SyntaxError
SignalException
Interrupt
StandardError
ArgumentError
IOError
EOFError
IndexError
LocalJumpError
NameError
NoMethodError
RangeError
FloatDomainError
RegexpError
RuntimeError
SecurityError
SystemCallError
SystemStackError
ThreadError
TypeError
ZeroDivisionError
SystemExit
fatal

have you tried adding an at_exit method in your class? This would allow you to do something when ruby is exiting. like in this article.
Ruby at_exit
or
From Ruby 2.0 API Docs
However beware of cleverly rescuing from an exception!
You'll start pulling your hair out down the road (or another dev will) when you try to figure out why your code isn't failing when it should be failing. I prefer to fail massively with a bright shiny sign saying the code failed here! hehe.
Good luck!

Related

ruby how to stop the execution after rescue

I have a func where when an exception was raised, I am rescuing it.
But the program continues to the next line and calls the next func create_request
But when there is exception, I do not want to continue
def validate_request_code options
if check_everything is good
#code to validate
else
errors << "something is gone bad"
end
[errors.size == 0, errors.size == 0 ? options : raise(ArgumentError, "Error while validating #{errors}")]
end
I am trying to catch/rescue the exception
def validate_request options
begin
validate_request_code options
rescue ArgumentError => e
log :error
rescue Exception => e
log :error
end
sleep 20
if options['action'] == "create"
create_request options
end
end
If by 'not continue' you mean that you want the original error to continue (i.e., you just want to take action on the way by), you can call raise inside the rescue block, which re-raises the original error.
def foo
begin
# stuff
rescue StandardError => e
# handle error
raise
end
end
You can also simply return from within the rescue block as well.
def foo
begin
# stuff
rescue StandardError => e
# handle error
return some_value
end
end
As an aside, generally you want to rescue StandardError rather than Exception. All the things that you can reasonably handle within your application are covered under the StandardError. The things outside that are things like out-of-memory, etc., that are outside your control.

Rescue from an error that may not be defined

My Rails website (this problem is purely Ruby based though) uses the AWS-SES (Action mailer using AWS) gem in test/development environment, and I am catching possible errors from email deliveries like this
def try_delivering_email(options = {})
begin
yield
return false
rescue EOFError,
...
AWS::SES::ResponseError,
... => e
log_exception(e, options)
return e
end
end
Now the problem is that this gem is only defined for specific environments, in other words AWS does not exist in development, and the error checking code will therefore throw an error (haha) for undefined constant.
I have tried substuting that line for (AWS::SES::ResponseError if defined?(AWS) but then the next error I get is
class or module required for rescue clause
How can I get around this in the nicest way possible ?
The exception list of a rescue-clause doesn't have to be a literal/static list:
excs = [EOFError]
defined?(AWS) && excs << AWS::SES::Response
# ...
rescue *excs => e
The splat operator * is used here to convert an array into a list.
You can't include a conditional in a rescue clause, but you can blind rescue and then get picky about how to deal with it using conventional Ruby code:
rescue EOFError => e
log_exception(e)
e
rescue => e
if (defined?(AWS) and e.is_a?(AWS::SES::Response))
# ...
else
raise e
end
end
It's not the nicest way, but it does the job. You could always encapsulate a lot of that into some module that tests more neatly:
def loggable_exception?(e)
case (e)
when EOFError, AnotherError, EtcError
true
else
if (defined?(AWS) and e.is_a?(AWS::SES::Response))
true
else
false
end
end
end
Then you can do this as that method name should be self-explanatory:
rescue => e
if (loggable_exception?(e))
log_exception(e)
e
else
raise e
end
end
You could make this a little neater if log_exception returned the exception it was given. Don't forget Ruby is "return by default" and it doesn't need to be explicit unless you're doing it early.

Rescue Exception with messages

I get exception Thrift::TransportException (end of file reached) and I want to rescue it with the message("end of file reached").
Now I do
begin
#...
rescue Thrift::TransportException => e
raise e unless "end of file reached" == e.message
# do whatever if it is not end of file reached.
end
Is there any method to do this rubyish?
If it can be avoided, don't depend on the message for logic - messages are just text and the developers of Thrift are free to change them at any given point in time, breaking your app.
TransportException in Thrift has a type, which is one of the constants you can see here. The one relevant for you is END_OF_FILE.
As for the implementation in code, there is no better way to check a property of the exception than doing it in the rescue block, so:
begin
#...
rescue Thrift::TransportException => e
raise e unless e.type == Thrift::TransportException::END_OF_FILE
# do whatever if it is not end of file reached.
end
You don't need to raise in a rescue block, i'll suggest take an instance variable show it wherever you want.Also, 1==a is very ugly, it's like blue is a sky
begin
#...
rescue Thrift::TransportException => e
#error = e.message if e.message == "end of file reached"
# do whatever if it is not end of file reached.
end

How to suppress and not to print the backtrace of the exception on the terminal in ruby using Thor?

Following is my method that might raise the exception.
Its a method of the CLI too that I am building.
Whenever the exception occurs, I want to catch that and just print my custom message on the terminal.
# variation 1
def self.validate(yaml_path)
begin
....
....
rescue
puts "Error"
end
end
# variation 2
def self.validate(yaml_path)
begin
....
....
rescue Exceptino => e
puts "Error: #{e.message}"
end
end
But the backtrace gets printed on the terminal.
How to avoid the backtrace to get printed?
± ../../bin/cf site create
ruby-1.8.7-p352
Error during processing: syntax error on line 52, col 10: ` - label: Price'
/Users/millisami/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/1.8/yaml.rb:133:in `load': syntax error on line 52, col 10: ` - label: Price' (ArgumentError)
.... backtrace .....
.............
The answer was to rescue it on the executable file at bin/<exe>.
Thanks for suggesting
begin
Cf::CLI.start
rescue Psych::SyntaxError
$stderr.puts "\n\tError during processing: #{$!.message}\n\n"
end
The following code doesn't output the backtrace.
class CLS
def hi
begin
raise "X"
rescue
puts $!.message
end
end
end
CLS.new.hi
Have you checked to see if there is another point in the stack where another method is rescuing the exception, outputting the stack trace and then re-raising the exception?
The reason you're not rescuing the exception is because Psych::SyntaxError is not descended from StandardError, so a simple rescue won't catch it. You need to specify a descendant of Psych::SyntaxError:
>> require 'psych'
=> true
>> begin; raise Psych::SyntaxError; rescue; puts "GOT IT"; end
# Psych::SyntaxError: Psych::SyntaxError
# from (irb):8
# from /Users/donovan/.rvm/rubies/ruby-1.9.2-p180/bin/irb:16:in `<main>'
>> Psych::SyntaxError.ancestors
=> [Psych::SyntaxError, SyntaxError, ScriptError, Exception, Object, PP::ObjectMixin, Kernel, BasicObject]
>> begin; raise Psych::SyntaxError; rescue Exception; puts "GOT IT"; end
GOT IT
Notice that in my example rescue Exception does catch it. You should generally be as specific as you can when rescuing unless you really need to rescue all Exceptions. Be aware that suppressing backtraces is good when the exception is something you expect, but if you don't expect it in general it makes debugging much harder.

Ruby Exceptions -- Why "else"?

I'm trying to understand exceptions in Ruby but I'm a little confused. The tutorial I'm using says that if an exception occurs that does not match any of the exceptions identified by the rescue statements, you can use an "else" to catch it:
begin
# -
rescue OneTypeOfException
# -
rescue AnotherTypeOfException
# -
else
# Other exceptions
ensure
# Always will be executed
end
However, I also saw later in the tutorial "rescue" being used without an exception specified:
begin
file = open("/unexistant_file")
if file
puts "File opened successfully"
end
rescue
file = STDIN
end
print file, "==", STDIN, "\n"
If you can do this, then do I ever need to use else? Or can I just use a generic rescue at the end like this?
begin
# -
rescue OneTypeOfException
# -
rescue AnotherTypeOfException
# -
rescue
# Other exceptions
ensure
# Always will be executed
end
The else is for when the block completes without an exception thrown. The ensure is run whether the block completes successfully or not. Example:
begin
puts "Hello, world!"
rescue
puts "rescue"
else
puts "else"
ensure
puts "ensure"
end
This will print Hello, world!, then else, then ensure.
Here's a concrete use-case for else in a begin expression. Suppose you're writing automated tests, and you want to write a method that returns the error raised by a block. But you also want the test to fail if the block doesn't raise an error. You can do this:
def get_error_from(&block)
begin
block.call
rescue => err
err # we want to return this
else
raise "No error was raised"
end
end
Note that you can't move the raise inside the begin block, because it'll get rescued. Of course, there are other ways without using else, like checking whether err is nil after the end, but that's not as succinct.
Personally, I rarely use else in this way because I think it's rarely needed, but it does come in handy in those rare cases.
EDIT
Another use case occurred to me. Here's a typical begin/rescue:
begin
do_something_that_may_raise_argument_error
do_something_else_when_the_previous_line_doesnt_raise
rescue ArgumentError => e
handle_the_error
end
Why is this less than ideal? Because the intent is to rescue when do_something_that_may_raise_argument_error raises ArgumentError, not when do_something_else_when_the_previous_line_doesnt_raise raises.
It's usually better to use begin/rescue to wrap the minimum code you want to protect from a raise, because otherwise:
you may mask bugs in the code that wasn't supposed to raise
the intention of rescue is harder to decipher. Someone (including your future self) may read the code and wonder "Which expression did I want to protect? It looks like expression ABC... but maybe expression DEF too???? What was the author intending?!" Refactoring becomes much more difficult.
You avoid those problems with this simple change:
begin
do_something_that_may_raise_argument_error
rescue ArgumentError => e
handle_the_error
else
do_something_else_when_the_previous_line_doesnt_raise
end
The else block in a begin rescue end block is used when you are perhaps expecting an exception of some sort to occur. If you run through all of your expected exceptions but still have nothing raised, then in your else block you can do whatever's needed now that you know that your original code ran error free.
The only reason I can see for the else block is if you want to execute something before the ensure block when the code in the begin block didn't raise any errors.
begin
puts "Hello"
rescue
puts "Error"
else
puts "Success"
ensure
puts "my old friend"
puts "I've come to talk with you again."
end
Thanks to else you sometimes can merge two nested begin end blocks.
So (simplified example from my current code) instead of:
begin
html = begin
NetHTTPUtils.request_data url
rescue NetHTTPUtils::Error => e
raise unless 503 == e.code
sleep 60
retry
end
redo unless html["market"]
end
you write:
begin
html = NetHTTPUtils.request_data url
rescue NetHTTPUtils::Error => e
raise unless 503 == e.code
sleep 60
retry
else
redo unless html["market"]
end

Resources