While the exception mechanism of
raise
and
rescue
is great
for abandoning execution when things go wrong, it's sometimes nice to
be able to jump out of some deeply nested construct during normal
processing. This is where
catch
and
throw
come in handy.
catch (:done) do
while gets
throw :done unless fields = split(/\t/)
songList.add(Song.new(*fields))
end
songList.play
end
|
catch
defines a block that is labeled with the given name
(which may be a
Symbol
or a
String
). The block is executed
normally until a
throw
is encountered.
When Ruby encounters a
throw
, it zips back up the call stack
looking for a
catch
block with a matching symbol.
When it finds
it, Ruby unwinds the stack to that point and terminates the block. If
the
throw
is called with the optional second parameter, that
value is returned as the value of the
catch
. So, in the previous
example, if the input does not contain correctly formatted lines, the
throw
will skip to the end of the corresponding
catch
, not
only terminating the
while
loop but also skipping the playing of
the song list.
The following example uses a
throw
to terminate interaction with
the user if ``!'' is typed in response to any prompt.
def promptAndGet(prompt)
print prompt
res = readline.chomp
throw :quitRequested if res == "!"
return res
end
catch :quitRequested do
name = promptAndGet("Name: ")
age = promptAndGet("Age: ")
sex = promptAndGet("Sex: ")
# ..
# process information
end
|
As this example illustrates, the
throw
does not have to appear within the
static scope of the
catch
.