Ruby Exception.to_s doesn't match expected string - ruby

I have a rescue block which checks for the correct exception thrown or not as follows:
rescue Exception
if $!.to_s() != "myException"
Err("Unexpected error :" + $!)
end
else
Err("No error")
My $!.to_s() contains large strings as follows when I puts like:
puts $!.to_s()
Output of above puts before if statement is:
myException \n
th sdfsj dsjhf sdfj \n
asdj jkds fdf j
So in if statement I want to compare the first line from output of $!.to_s() with string in double quotes.
Any suggestions how to resolve this?

That makes my eyes hurt. Please do object-oriented programming in ruby.
class MyException < StandardError; end
will define a new exception you can rescue by
begin
do_something_that_raises_expected_exception
rescue MyException
do_something_else
end
So you won't need any String comparison.
If you want to go down your road, use string.match exception_name, but I advise against it.
Another word on rescuing: Don't do rescue Exception if possible, just use rescue, because Exception captures stuff like SyntaxError too (which is likely not intended). And exceptions are frowned upon for flow control in ruby, as opposed to python.

Although I fully agree with Tass, here is how you can achieve what you want:
if $!.to_s !~ /\AmyException\s*\n/
...
or
if $!.to_s.lines.first != "myException \n"
...
But please: Don't do that.

Related

What are the empty single quotes for after rescue?

while t = Integer(gets.chomp) rescue ''
if t.is_a? Integer
break
else
print "Please enter a whole number "
end
end
I'm just trying to figure out exactly why I need those empty single quotes after rescue for this loop to work.
because Integer(gets.chomp) can raise an exception, which caught by rescue and assign to t value as empty string
This is referred to as an inline rescue. If t = Integer(gets.chomp) raises any exception inheriting from StandardError it will be rescued and an empty string will be returned instead. You can think of it like this:
begin
do_something
rescue
''
end
The problem with this approach is that you can't specify exception classes to rescue from, so you may accidentally mask errors that you didn't expect, like a NoMethodError raised when misspelling the chomp method:
Integer(gets.chmp) rescue ''
#=> ""

Ruby Syntax of '=>' (hashrocket)

I tried this earlier and everyone got off on rescue block syntax. Please don't go there. Given the following working code:
begin
(1..1000).each do |i|
puts i
sleep 1
end
rescue Exception => e
puts "\nCaught exception..."
puts "Exception class: #{e.class}"
end
Pressing CTRL+C while it is running prints out "Caught exception...", as expected. What exactly is going on syntax wise in the rescue line, particularly between Exception and the variable e with the => in between?
The word "rescue" is a keyword... part of the ruby language. "e" is a variable, and could just as functionally be "a", "b", or "c". The following code works just as well.
begin
(1..1000).each do |i|
puts i
sleep 1
end
rescue Exception => b
puts "\nCaught exception..."
puts "Exception class: #{b.class}"
end
What are "Exception" and "=>"? Is there another way to write this expression to make it more intelligible from a syntactical point of view? I don't think we're dealing with a hash here because the following code compiles but throws an error as soon as CTRL+C is pressed (undefined local variable or method `e').
begin
(1..1000).each do |i|
puts i
sleep 1
end
rescue { Exception => b }
puts "\nCaught exception..."
puts "Exception class: #{b.class}"
end
Can someone explain what is going on? and specifically what language element '=>' (hashrocket) is in this specific example since it seems to have nothing to do with hashes?
I'm sorry to inform you that this is just one-off syntax that doesn't really have any relation to other Ruby syntax.
Given the expression:
begin
# ...
rescue FooError, BarError => ex
# ...
end
FooError, BarError is the list of exception classes (usually subclasses of StandardError) that will be rescued. This behaves just like an argument list, so you can (if you want) do stuff like this:
my_exception_classes = [ FooError, BarError ]
begin
# ...
rescue *my_exception_classes => ex
# ...
end
It's worth noting that you shouldn't, generally, use Exception here because it will rescue all exceptions, including things like SignalException::Interrupt and NoMemoryError, which usually isn't what you want.
=> is just syntax, and arguably not the best choice of syntax for the reason that it leads to questions like your own.
ex is the name of a local variable into which the exception object will be put.
Digging deeper
If you're into reading parser grammars, it's always fun looking at Ruby's YACC grammar in parse.y. It's not especially easy to read, but we can see the grammar for a rescue expression, called opt_rescue in the grammar, here:
opt_rescue : k_rescue exc_list exc_var then
compstmt
opt_rescue
k_rescue is of course the keyword rescue. exc_list is the list of exception classes which, like I said, is just like an argument list:
exc_list : arg_value
exc_var is the part where the variable to put the exception in is designated:
exc_var : tASSOC lhs
And here, tASSOC is of course our friend the hashrocket (=>), and lhs, i.e. “left-hand side,” is an expression you'd find to the left of an assignment expression (like, say, the name of a variable).
compstmt is basically “any valid Ruby code,” and then there’s opt_rescue again, since you can (optionally) have many rescues in a begin or def block.
As you can see, the only thing this syntax has in common with a Hash is tASSOC.

How to know what exceptions to rescue

I want a class that will load and save settings in yaml file, and displays an error if something happens. I must catch exceptions and I must know what to catch. There is no guarantee what exception will be raised; user might press CTRL+C or memory may run out, but YAML.load_file can raise only a limited number of exceptions. There is nowhere listed what exceptions a function YAML.load_file might raise.
How can I catch only them when I don't know what those exceptions are?
This question has been asked, but there is no real answer:
How to know what exceptions to rescue? Answer is about exceptions in general
How to deal with not knowing what exceptions can be raised by a library method in Ruby?
Ruby How to know what to rescue?
Where to find (or how to read) ruby documentation?
Documentation for Ruby exceptions
Sometimes you just don't know which kind of exception can be thrown, for that the generic rescue catching exists.
begin
do_something
rescue KnownException
treat_exception
# generic exception
rescue Exception => e
# you don't know which exception has been raised but all info is in e
print "Ups I don't know this Exception:#{e.class} error: #{e.message}"
raise
end
How can I catch only them when I don't know what those exceptions are?
What are you going to do when you catch them, I wonder? It makes little sense to catch exceptions for the sake of catching. Swallowing exceptions is especially bad practice.
My rule of thumb is: catch only those I can recover from (this implies already knowing what they are). Let the rest bubble up and crash the program or possibly be catched in one of outer scopes (which will know how to recover from this concrete one).
How to discover currently loaded exception classes
This almost 10 year old code snippet still works today:
exceptions = []
tree = {}
ObjectSpace.each_object(Class) do |cls|
next unless cls.ancestors.include? Exception
next if exceptions.include? cls
exceptions << cls
cls.ancestors.delete_if {|e| [Object, Kernel].include? e }.reverse.inject(tree) {|memo,cls| memo[cls] ||= {}}
end
indent = 0
tree_printer = Proc.new do |t|
t.keys.sort { |c1,c2| c1.name <=> c2.name }.each do |k|
space = (' ' * indent); space ||= ''
puts space + k.to_s
indent += 2; tree_printer.call t[k]; indent -= 2
end
end
tree_printer.call tree
Run it in the rails console and you'll see a lot of exception classes. :)
The source code is the documentation.
-- Matz

string conversion of $!

I am trying to handle an exception caused by this following code:
begin
reader = CSV.open(ARGV[0],col_sep=";")
rescue
puts "exception: " + $!
exit
end
Unfortunately I cannot display correctly the message, Ruby does not interpret $! as string and neither seems to be able to convert it correctly:
$ ruby.exe fixcsv.rb csvfile
fixcsv.rb:11:in `+': can't convert ArgumentError into String (TypeError)
from fixcsv.rb:11:in `rescue in <main>'
from fixcsv.rb:8:in `<main>'
I really cannot understand why this happens; the following tutorial displays similar code that obviously takes into account a correct string conversion of $!:
http://ruby.activeventure.com/programmingruby/book/tut_exceptions.html
Has this anything to do with the fact that I did not explicitly set the exception class?
While I would recommend doing what fl00r did (Exception => e), you can still use $! if you really want to:
begin
reader = CSV.open(ARGV[0],col_sep=";")
rescue
puts "exception: " + $!.message
exit
end
begin
reader = CSV.open(ARGV[0],col_sep=";")
rescue Exception => e
puts "exception: #{e.message}"
end
You don't even need to add .message to e, from #fl00r's example:
begin
reader = CSV.open(ARGV[0],col_sep=";")
rescue Exception => e
puts "exception: #{e}"
end
What happens is that Ruby calls .to_s on the exception e. Exceptions implement to_s, they merely don't implement to_str, which is what "exception: " + $! tried to do.
The difference between to_s and to_str is that the former means "You can change me into a string, but I'm not like a string at all", whereas the latter means "Not only can you change me into a string, but I'm very much like a string". Jorg W Mittag's discussion on to_s versus to_str is well worth reading.

Is there a functional version of begin...rescue...end (exception block) in ruby?

I'd like to do something like this in ruby:
safe_variable = begin
potentially_nil_variable.foo
rescue
some_other_safe_value
end
... and treat the exception block (begin/rescue/end) as a function/block. This doesn't work as written, but is there a way to get a similar result?
NB what I'm actually doing is this, which works but is IMO ugly:
begin
safe_variable = potentially_nil_variable.foo
rescue
safe_variable = some_other_safe_value
end
UPDATE
I guess I hit a corner case on ruby syntax. What I actually was doing was this:
object_safe = begin potentially_nil_variable.foo
rescue ""
end
The error was class or module required for rescue clause. Probably it thought that "" was supposed to be the placeholder for the exception result.
The form you have should work:
safe_variable = begin
potentially_nil_variable.foo
rescue
some_other_safe_value
end
A shorter form:
safe_variable = this_might_raise rescue some_other_safe_value
If you're only avoiding nil, you can look into ActiveRecord's try:
safe_variable = potentially_nil_variable.try(:foo) || some_other_safe_value
The most functional approach I know of for sending a message to an object that might be nil is something like andand. For nil, andand returns an object that will simply return nil no matter what message you send it. For other objects, it returns the original object. And pretty much anything will be more efficient than mucking around with exceptions.

Resources