GGarramuno wrote:
In the above example, by placing the catch where it is, the way I read
it was that $stdin.getc gets run only once, instead of in each
iteration (ie. the while condition is not evaluated as it is OUTSIDE
the catch do/end, just as is the ensure block)? This is what’s
loosing me. What’s the logic -magic- that makes it all work?
“catch” is just a method. All it does is evaluate the block that you
attach to it. If, “inside” of that block (ie, directly, or via methods
called from within the block), the “throw” method is called (note that
it is also a method), AND if the symbol passed to the throw method
matches the one for the given catch method, THEN the catch method
terminates, returning the (optional) value passed to the throw method.
catch(:some_symbol) do
do_something
do_something_else
catch(:another_symbol) do
do_yet_another_thing
throw :some_symbol
end
end
In the above example, the ‘throw’ passes control back to the outermost
catch invocation, which terminates.
Or to put in another way, what if I wanted to have a catch() that is
inside the first while loop but does not evaluate the condition nor
runs the ensure block (say, just to backtrace the code like an ugly
goto command)? How would that look like? Or that’s just not possible
(and thus it explains why the above thing always gets interpreted the
way we intended)?
There is no way (that I know of) to ‘throw’ within a protected region
(ie, one inside of a ‘begin’…‘end’, with rescue clauses and an ensure
clause) without executing the associated ensure block. ‘catch’ is very
much like a goto, but it makes sure that ‘ensure’ clauses are all
executed on its way out.
Hope that helps…kind of.
···
–
Jamis Buck
jgb3@email.byu.edu
ruby -h | ruby -e ‘a=;readlines.join.scan(/-(.)[e|Kk(\S*)|le.l(…)e|#!(\S*)/) {|r| a << r.compact.first };puts “\n>#{a.join(%q/ /)}<\n\n”’