Dan Debertin (airboss / nodewarrior.org) wrote:
>  I was reminded of this problem by the recent 'breaking out of case'
>  thread. I have a 'case' statement that evaluates a condition:
>  
>  case cond
>  when 'thing1'
>    ...do thing1 stuff...
>  when 'thing2'
>    ...do thing2 stuff...
>    cond = 'thing1'
>  end
>
>  The 'thing2' clause changes the value of 'cond', so I want to be able
>  to bounce back to the top and re-evaluate the case. The way I ended up
>  doing it was:

Abstract the desired behavior into methods or functions of their own:

def restartable
  yield
end

restartable do
  case cond
  ...
  when 'thing2'
    ...do thing2 stuff...
    cond = 'thing1'
    redo
  end
end

Note that using 'redo' is not necessary. We can go with catch & throw,
and define a 'restart' function instead, and then we can also do it from
inside blocks:

def restartable
  done = false
  until done do
    catch (:restart) do
      yield
      done = true
    end
  end
end

def restart
  throw :restart
end

restartable do
  case cond
  ...
  when 'thing2'
    ...do thing2 stuff...
    cond = 'thing1'
    array.each {|x| restart if x == foo}
  end
end

This approach can of course be generalized to all sorts of behaviors.

[...]

			Reimer Behrends