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.
Related
I have been searching thoroughly on Google but I can't seem to be able to find the answer. I am wondering what the => operator means in the Ruby code shown below:
def test_raising_a_particular_error
result = nil
begin
# 'raise' and 'fail' are synonyms
raise MySpecialError, "My Message"
rescue MySpecialError => ex
result = :exception_handled
end
assert_equal :exception_handled, result
assert_equal "My Message", ex.message
end
There is no => operator in Ruby. There are, however, two uses of => in Ruby:
in a Hash literal between the key object and the value object
in a rescue clause after the exception filter expression, naming the variable the exception should be bound to
So, in this case, it's #2, and means "rescue any exception that is an instance of MySpecialError and bind it to the local variable named ex".
A quick query:
How would a Java programmer will understand the following Ruby statement:
rescue ErrorType1, ErrorType2 => ex
That is, I want to put brackets/parenthesis around it explicitly.
So, is it?
rescue(ErrorType1, {ErrorType2 => ex})
or,
rescue({[ErrorType1, ErrorType2] => ex})
or, something else...
About the syntax:
rescue ErrorType1, ErrorType2 => ex
Please note following:
There is no hash involved
'rescue' is not a method, you can't even write it as rescue(ErrorType1, ErrorType2 => ex)
Ruby places a reference to raised associated exception into the
global variable $!.
In the above form, the 'rescue' takes a special argument where
you give the name of a local variable to receive the matched
exception, which is more readable then using $!.
Now, look at the syntax again...
rescue is a control structure with it's own syntax, it's not a method call, so your 2nd and 3rd code blocks are invalid syntax, you aren't not passing any arguments.
rescue <exception-class1>[, <exception-class2>] => <a variable to assign the exception to>
so when doing rescue TypeError, StandardError => my_exception it will catch any TypeError or StandardError exception that is raised and assign it to the my_exception local variable.
I suggest the recently translated Ruby Hacking Guide (search for "rescue").
Look at the below code :
begin
a=1/0
rescue => e
p e.class
p defined?(e)
end
# >> ZeroDivisionError
# >> "local-variable"
Where e is a local variable to that exception handling block. In Ruby local variables are created using assignment operation,but in case of exception handling,reference to the currently raised exception is assigned to the local variable e using the hash rocket(=>),instead of =. This is as per design. Don't think of that it is a Hash.
In Ruby we use one or more rescue clauses to tell Ruby the types of exceptions we want to handle.If you write a rescue clause with no parameter list, the parameter defaults to StandardError. Each rescue clause can specify multiple exceptions to catch. At the end of each rescue clause you can give Ruby the name of a local variable to receive the matched exception. The parameters to the rescue clause can also be arbitrary expressions (including method calls) that return an Exception class. If we use raise with no parameters, it re-raises the exception.Handling an Exception
Out of three of your codes only valid is rescue ErrorType1, ErrorType2 => ex. Others will give you syntax error.
Hierarchy(partial) :
StandardError
|
IndexError
|
KeyError
You can specify the error class names as arguments to the rescue list,in any order.On runtime ruby will pick up the correct one from the list. Look the code below :
begin
a = {}
a.fetch(:b)
rescue StandardError,KeyError,IndexError => e
p e.class
end
# >> KeyError
begin
a = {}
a.fetch(:b)
rescue KeyError,StandardError,IndexError => e
p e.class
end
# >> KeyError
If you think,you would tell Ruby interpreter on runtime, which one to match first using paren from the argument list,Ruby will not allow you to do so,in return it will throw to you syntax error. Same also for below :
begin
a = {}
a.fetch(:b)
rescue StandardError => e1
p e1.class
rescue IndexError => e2
p e2.class
rescue KeyError => e3
p e3.class
end
# >> KeyError
Note: If we want to catch more exception classes, we can just write them in line. When we want to handle different errors differently, we can specify several rescue clauses.Ruby Hacking Guide
The rescue which could assigns a variable to reference the error object has this syntax (=>)
rescue => e
If rescue is the one of the general method call, what's the meaning of =>.
Could I use the same syntax on other method call?
my_method arg1, arg2 => my_obj
While raise is indeed a method, rescue is not. It is a keyword and defined on parse.y:10467. As such, the syntax you have is special to rescue (since => e isn't any sort of method argument), and not valid for methods themselves (at least not with the same meaning). How/where the rescue => e syntax itself is defined in the parser I'm not entirely sure.
As some football coach/philosopher-king might say, it is what it is. Here's Ruby's parse.y. Of particular interest is this part:
opt_rescue : keyword_rescue exc_list exc_var then
compstmt
opt_rescue
...
| none
;
exc_list : arg_value
...
| mrhs
...
| none
;
exc_var : tASSOC lhs
...
| none
;
Explanation
exc_list basically allows nothing, an exception type, or a (splatted) series of exceptions like rescue ZeroDivisionError, LoadError
exc_var can be nothing or => some_variable
opt_rescue can therefore be rescue by itself or plus either or both of the above.
It's only listed here as special syntax for assignment for exceptions. The only other use for => is for key-value association.
Note also that arg_value and mrhs are on the left-hand side and lhs is on the right-hand side, which is as far as I can tell the only place where this occurs. Someone correct me if I'm wrong here, but there isn't any other "backwards" assignment in parse.y.
No, the syntax in the rescue is only used there. If you use the hash rocket '=>' in a function call like that, it will be interpreted as a hash, and if arg2 was not defined as a variable previously, it will be an error.
def foo(a,b)
puts b.inspect
end
foo "bar", :baz => 5 #=> {:baz=>5}
foo "bar", baz => 5 #=> NameError: undefined local variable or method `baz'
baz = "flux"
foo "bar", baz => 5 #=> {"flux"=>5}
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.
temp = 98.3
begin
print "Your temperature is " + temp.to_s + " Fahrenheit. "
puts "I think you're okay."
temp += 0.1
end while temp < 98.6
In the above example, is everything between begin and end a block?
I'm still confused what a block is.
If you can't call it a block, what would you call that chunk of code between begin and end? Is it ok to call it a chunk?
Block has a special meaning in Ruby. According to Matz, Ruby's creator, you can look at a block as a nameless function - typically something that can be yielded into, and which may also take parameters.
You may see the following kind of disamiguation when describing Ruby syntax:
begin...end (what is called block in other languages) may sometimes be referred to simply as what it is, i.e. an expression (which may in turn contain other expressions - an expression is simply something that has a return value) in Ruby. Some references will still call it a begin/end block, or a code block, adding somewhat to the confusion
do...end or {...} will always be referred to as a block in Ruby
For examples, peruse the the Ruby syntax man page, e.g.
begin expression end
expression while expression
loop block
For further reading, see:
Programming Ruby
Ruby (from other languages)
Much, much more documentation
begin/end are strictly control flow, not blocks.
begin
puts "hi"
end
# => "hi"
The code runs immediately. If it was a block, it would have to been called somehow in order for the code in it to run, as in this example:
def a_method; end
a_method { puts "hi" }
# nothing..
def a_method
yield
end
a_method { puts "Hi!" }
# => "Hi!"