aboutsummaryrefslogtreecommitdiffstats
path: root/Library/Homebrew/debrew/raise_plus.rb
blob: 29bf4106a1b4b809810ea114f185277eb8f8840b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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