Now there might be a reason why the do..end, or {..} of a block can't
have the same feature, but I'm scratching my head to figure out why.
You CAN have a block which contains a single statement with a rescue
modifier:
lambda do
raise "help!" rescue "gotcha"
end
is legal as is the semantically equivalent:
lambda {raise "help!" rescue "gotcha"}
These two example illustrate the ability to attach a rescue modifier
to a method call.
The fact that in these example the method calls are sitting by
themselves inside
a block is irrelevant--the rescue is associated with the call and not
with
the enclosing block. You can attach a rescue clause to any statement:
(3/0) rescue "divide by zero"
[1,2,3].map {|x| x/0 } rescue "divide by zero"
I think is important to view blocks as part of the syntax of a method
call
in the same way that the period, parenthesis, and commas are part of
the syntax
of a method call:
receiver.method(arg1, arg2) { #code in a block }
So 'rescue', when it is attached to a single method call, is really
part of the
syntax of the method call and the surrounding context is of no concern.
You can even have a rescue right in the middle of actual arguments:
a = Array.new( 3/0 ) # raises ZeroDivisionError
a = Array.new( (3/0 rescue 100) ) # creates an array with 100 entries
Note: I first tried that last example without the extra set of parens
and the
parser didn't like it: Array.new( 3/0 rescue 100 ). Seems like an
interesting
corner case on statement/expression parsing.
Anyway, my point is that rescue modifiers and their semantics are
orthogonal to
block syntax (do/end {} ) and its semantics.
lambda do
raise "help!"
rescue
"gotcha"
end
is not.
In this example, the rescue is *not* a modifier of the method call
'raise'. The
parser has fully processed the raise and is attempting to parse the
next method call.
In that case rescue is not valid because do/end blocks do not open a
new exception
context in the way that a method call or begin/end block do.
It might be easier to see what is going on from a parsing standpoint
by substituting
semicolons for newlines:
lambda do
raise "help!" rescue "gotcha" # one statement, a call to raise
end
lambda do
raise "help!"; rescue "gotcha" # two statements, second one invalid
end
The method/statement modifier version of 'rescue' is syntactically
different than
the version of 'rescue' attached to method definitions or begin/end
blocks.
This may not have clarified the question regarding *why* do/end
blocks don't
create a new exception scope but hopefully it clarifies the syntax
associated with
a rescue modifier clause.
Gary Wright