File: throw_symbol.rb

package info (click to toggle)
ruby-rspec 3.13.0c0e0m0s1-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 6,856 kB
  • sloc: ruby: 70,868; sh: 1,423; makefile: 99
file content (138 lines) | stat: -rw-r--r-- 4,050 bytes parent folder | download | duplicates (2)
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
128
129
130
131
132
133
134
135
136
137
138
module RSpec
  module Matchers
    module BuiltIn
      # @api private
      # Provides the implementation for `throw_symbol`.
      # Not intended to be instantiated directly.
      class ThrowSymbol
        include Composable

        def initialize(expected_symbol=nil, expected_arg=nil)
          @expected_symbol = expected_symbol
          @expected_arg = expected_arg
          @caught_symbol = @caught_arg = nil
        end

        # rubocop:disable Metrics/MethodLength
        # @private
        def matches?(given_proc)
          @block = given_proc
          return false unless Proc === given_proc

          begin
            if @expected_symbol.nil?
              given_proc.call
            else
              @caught_arg = catch :proc_did_not_throw_anything do
                catch @expected_symbol do
                  given_proc.call
                  throw :proc_did_not_throw_anything, :nothing_thrown
                end
              end

              if @caught_arg == :nothing_thrown
                @caught_arg = nil
              else
                @caught_symbol = @expected_symbol
              end
            end

            # Ruby 1.8 uses NameError with `symbol'
            # Ruby 1.9 uses ArgumentError with :symbol
          rescue NameError, ArgumentError => e
            unless (match_data = e.message.match(/uncaught throw (`|\:)([a-zA-Z0-9_]*)(')?/))
              other_exception = e
              raise
            end
            @caught_symbol = match_data.captures[1].to_sym
          rescue => other_exception
            raise
          ensure
            # rubocop:disable Lint/EnsureReturn
            unless other_exception
              if @expected_symbol.nil?
                return !!@caught_symbol
              else
                if @expected_arg.nil?
                  return @caught_symbol == @expected_symbol
                else
                  return (@caught_symbol == @expected_symbol) && values_match?(@expected_arg, @caught_arg)
                end
              end
            end
            # rubocop:enable Lint/EnsureReturn
          end
        end
        # rubocop:enable Metrics/MethodLength

        def does_not_match?(given_proc)
          !matches?(given_proc) && Proc === given_proc
        end

        # @api private
        # @return [String]
        def failure_message
          "expected #{expected} to be thrown, #{actual_result}"
        end

        # @api private
        # @return [String]
        def failure_message_when_negated
          "expected #{expected('no Symbol')}#{' not' if @expected_symbol} to be thrown, #{actual_result}"
        end

        # @api private
        # @return [String]
        def description
          "throw #{expected}"
        end

        # @api private
        # Indicates this matcher matches against a block.
        # @return [True]
        def supports_block_expectations?
          true
        end

        # @api private
        def supports_value_expectations?
          false
        end

        # @api private
        def expects_call_stack_jump?
          true
        end

      private

        def actual_result
          return "but was not a block" unless Proc === @block
          "got #{caught}"
        end

        def expected(symbol_desc='a Symbol')
          throw_description(@expected_symbol || symbol_desc, @expected_arg)
        end

        def caught
          throw_description(@caught_symbol || 'nothing', @caught_arg)
        end

        def throw_description(symbol, arg)
          symbol_description = symbol.is_a?(String) ? symbol : description_of(symbol)

          arg_description = if arg
                              " with #{description_of arg}"
                            elsif @expected_arg && @caught_symbol == @expected_symbol
                              " with no argument"
                            else
                              ""
                            end

          symbol_description + arg_description
        end
      end
    end
  end
end