Last active
April 21, 2024 18:57
-
-
Save everton/c1b0b553df2e656c88a01249688e6218 to your computer and use it in GitHub Desktop.
Inspired by Common LISP conditions system, this code here uses continuations to inject "restart" options from the context where an Exception was raised and allowing to resume from the error line. Obs.: since this code relies on continuations, it is not supposed to work on Ruby implementations without this resource (such as JRuby, Ribinius, etc)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'continuation' | |
class Restart < RuntimeError | |
attr_accessor :menu | |
def initialize(**menu) | |
@menu = menu | |
@menu.each do |name, proc| | |
define_singleton_method "#{name}!" do | |
proc.call | |
end | |
end | |
end | |
end | |
begin | |
x = 10 | |
callcc do |c| | |
raise Restart.new \ | |
resume: -> { c.call }, | |
inc_x: -> { x += 1; c.call } | |
end | |
puts "x: #{x}" | |
rescue Restart => e | |
# binding.irb | |
puts "Restart options:" | |
e.menu.keys.each_with_index do | |
puts " - #{_2 + 1}: #{_1}" | |
end | |
e.inc_x! | |
end |
After I worked on this experiment, I found this blog post (from almost 20 years ago!) with a better approach and also porting the example from the Practical Common LISP book (which explains very well why to use this):
https://leahneukirchen.org/blog/archive/2005/03/restartable-exceptions.html
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The output of running this using MRI Ruby is like: