47 lines
		
	
	
		
			1.3 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
			
		
		
	
	
			47 lines
		
	
	
		
			1.3 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
| require 'continuation' if RUBY_VERSION.to_f >= 1.9
 | |
| 
 | |
| class Exception
 | |
|   attr_accessor :continuation
 | |
| 
 | |
|   def restart(&block)
 | |
|     continuation.call block
 | |
|   end
 | |
| end
 | |
| 
 | |
| module RaisePlus
 | |
|   alias :original_raise :raise
 | |
| 
 | |
|   private
 | |
| 
 | |
|   def raise(*args)
 | |
|     exception = case
 | |
|                 when args.size == 0
 | |
|                   $!.nil? ? RuntimeError.exception : $!
 | |
|                 when args.size == 1 && args[0].is_a?(String)
 | |
|                   RuntimeError.exception(args[0])
 | |
|                 when args.size == 2 && args[0].is_a?(Exception)
 | |
|                   args[0].exception(args[1])
 | |
|                 when args[0].is_a?(Class) && args[0].ancestors.include?(Exception)
 | |
|                   args[0].exception(args[1])
 | |
|                 else
 | |
|                   args[0]
 | |
|                 end
 | |
| 
 | |
|     # passing something other than a String or Exception is illegal, but if someone does it anyway,
 | |
|     # that object won't have backtrace or continuation methods. in that case, let's pass it on to
 | |
|     # the original raise, which will reject it
 | |
|     return super exception unless exception.is_a?(Exception)
 | |
| 
 | |
|     # keep original backtrace if reraising
 | |
|     exception.set_backtrace(args.size >= 3 ? args[2] : caller) if exception.backtrace.nil?
 | |
| 
 | |
|     blk = callcc do |cc|
 | |
|       exception.continuation = cc
 | |
|       super exception
 | |
|     end
 | |
|     blk.call unless blk.nil?
 | |
|   end
 | |
| 
 | |
|   alias :fail :raise
 | |
| end
 | 
