summaryrefslogtreecommitdiff
path: root/spec/ruby/core/kernel/catch_spec.rb
blob: 4060172429a4a1b6662c0e3b36db7ea5337c7e46 (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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
require_relative '../../spec_helper'
require_relative 'fixtures/classes'

describe "Kernel.catch" do
  before :each do
    ScratchPad.clear
  end

  it "executes its block and catches a thrown value matching its argument" do
    catch :thrown_key do
      ScratchPad.record :catch_block
      throw :thrown_key
      ScratchPad.record :throw_failed
    end
    ScratchPad.recorded.should == :catch_block
  end

  it "returns the second value passed to throw" do
    catch(:thrown_key) { throw :thrown_key, :catch_value }.should == :catch_value
  end

  it "returns the last expression evaluated if throw was not called" do
    catch(:thrown_key) { 1; :catch_block }.should == :catch_block
  end

  it "passes the given symbol to its block" do
    catch :thrown_key do |tag|
      ScratchPad.record tag
    end
    ScratchPad.recorded.should == :thrown_key
  end

  it "raises an ArgumentError if a Symbol is thrown for a String catch value" do
    -> { catch("exit") { throw :exit } }.should raise_error(ArgumentError)
  end

  it "raises an ArgumentError if a String with different identity is thrown" do
    -> { catch("exit") { throw "exit" } }.should raise_error(ArgumentError)
  end

  it "catches a Symbol when thrown a matching Symbol" do
    catch :thrown_key do
      ScratchPad.record :catch_block
      throw :thrown_key
    end
    ScratchPad.recorded.should == :catch_block
  end

  it "catches a String when thrown a String with the same identity" do
    key = "thrown_key"
    catch key do
      ScratchPad.record :catch_block
      throw key
    end
    ScratchPad.recorded.should == :catch_block
  end

  it "accepts an object as an argument" do
    catch(Object.new) { :catch_block }.should == :catch_block
  end

  it "yields an object when called without arguments" do
    catch { |tag| tag }.should be_an_instance_of(Object)
  end

  it "can be used even in a method different from where throw is called" do
    class CatchSpecs
      def self.throwing_method
        throw :blah, :thrown_value
      end
      def self.catching_method
        catch :blah do
          throwing_method
        end
      end
    end
    CatchSpecs.catching_method.should == :thrown_value
  end

  describe "when nested" do
    before :each do
      ScratchPad.record []
    end

    it "catches across invocation boundaries" do
      catch :one do
        ScratchPad << 1
        catch :two do
          ScratchPad << 2
          catch :three do
            ScratchPad << 3
            throw :one
            ScratchPad << 4
          end
          ScratchPad << 5
        end
        ScratchPad << 6
      end

      ScratchPad.recorded.should == [1, 2, 3]
    end

    it "catches in the nested invocation with the same key object" do
      catch :thrown_key do
        ScratchPad << 1
        catch :thrown_key do
          ScratchPad << 2
          throw :thrown_key
          ScratchPad << 3
        end
        ScratchPad << 4
      end

      ScratchPad.recorded.should == [1, 2, 4]
    end
  end

  it "raises LocalJumpError if no block is given" do
    -> { catch :blah }.should raise_error(LocalJumpError)
  end
end

describe "Kernel#catch" do
  it "is a private method" do
    Kernel.should have_private_instance_method(:catch)
  end
end