rspec-expectations 2.14.0 → 3.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data/.document +1 -1
  4. data/.yardopts +1 -1
  5. data/Changelog.md +976 -25
  6. data/{License.txt → LICENSE.md} +5 -3
  7. data/README.md +162 -26
  8. data/lib/rspec/expectations/block_snippet_extractor.rb +253 -0
  9. data/lib/rspec/expectations/configuration.rb +230 -0
  10. data/lib/rspec/expectations/expectation_target.rb +127 -51
  11. data/lib/rspec/expectations/fail_with.rb +17 -57
  12. data/lib/rspec/expectations/failure_aggregator.rb +229 -0
  13. data/lib/rspec/expectations/handler.rb +146 -32
  14. data/lib/rspec/expectations/minitest_integration.rb +58 -0
  15. data/lib/rspec/expectations/syntax.rb +68 -100
  16. data/lib/rspec/expectations/version.rb +1 -1
  17. data/lib/rspec/expectations.rb +58 -23
  18. data/lib/rspec/matchers/aliased_matcher.rb +116 -0
  19. data/lib/rspec/matchers/built_in/all.rb +86 -0
  20. data/lib/rspec/matchers/built_in/base_matcher.rb +191 -20
  21. data/lib/rspec/matchers/built_in/be.rb +114 -114
  22. data/lib/rspec/matchers/built_in/be_between.rb +77 -0
  23. data/lib/rspec/matchers/built_in/be_instance_of.rb +15 -4
  24. data/lib/rspec/matchers/built_in/be_kind_of.rb +10 -1
  25. data/lib/rspec/matchers/built_in/be_within.rb +35 -18
  26. data/lib/rspec/matchers/built_in/change.rb +389 -80
  27. data/lib/rspec/matchers/built_in/compound.rb +290 -0
  28. data/lib/rspec/matchers/built_in/contain_exactly.rb +310 -0
  29. data/lib/rspec/matchers/built_in/count_expectation.rb +169 -0
  30. data/lib/rspec/matchers/built_in/cover.rb +3 -0
  31. data/lib/rspec/matchers/built_in/eq.rb +30 -8
  32. data/lib/rspec/matchers/built_in/eql.rb +23 -8
  33. data/lib/rspec/matchers/built_in/equal.rb +55 -22
  34. data/lib/rspec/matchers/built_in/exist.rb +74 -10
  35. data/lib/rspec/matchers/built_in/has.rb +141 -22
  36. data/lib/rspec/matchers/built_in/have_attributes.rb +114 -0
  37. data/lib/rspec/matchers/built_in/include.rb +184 -32
  38. data/lib/rspec/matchers/built_in/match.rb +95 -1
  39. data/lib/rspec/matchers/built_in/operators.rb +128 -0
  40. data/lib/rspec/matchers/built_in/output.rb +207 -0
  41. data/lib/rspec/matchers/built_in/raise_error.rb +192 -44
  42. data/lib/rspec/matchers/built_in/respond_to.rb +154 -28
  43. data/lib/rspec/matchers/built_in/satisfy.rb +39 -9
  44. data/lib/rspec/matchers/built_in/start_or_end_with.rb +94 -0
  45. data/lib/rspec/matchers/built_in/throw_symbol.rb +58 -14
  46. data/lib/rspec/matchers/built_in/yield.rb +240 -161
  47. data/lib/rspec/matchers/built_in.rb +47 -33
  48. data/lib/rspec/matchers/composable.rb +171 -0
  49. data/lib/rspec/matchers/dsl.rb +531 -10
  50. data/lib/rspec/matchers/english_phrasing.rb +58 -0
  51. data/lib/rspec/matchers/fail_matchers.rb +42 -0
  52. data/lib/rspec/matchers/generated_descriptions.rb +14 -8
  53. data/lib/rspec/matchers/matcher_delegator.rb +61 -0
  54. data/lib/rspec/matchers/matcher_protocol.rb +105 -0
  55. data/lib/rspec/matchers/multi_matcher_diff.rb +82 -0
  56. data/lib/rspec/matchers.rb +520 -173
  57. data.tar.gz.sig +0 -0
  58. metadata +141 -242
  59. metadata.gz.sig +2 -0
  60. data/features/README.md +0 -48
  61. data/features/Upgrade.md +0 -53
  62. data/features/built_in_matchers/README.md +0 -90
  63. data/features/built_in_matchers/be.feature +0 -175
  64. data/features/built_in_matchers/be_within.feature +0 -48
  65. data/features/built_in_matchers/cover.feature +0 -47
  66. data/features/built_in_matchers/end_with.feature +0 -48
  67. data/features/built_in_matchers/equality.feature +0 -139
  68. data/features/built_in_matchers/exist.feature +0 -45
  69. data/features/built_in_matchers/expect_change.feature +0 -59
  70. data/features/built_in_matchers/expect_error.feature +0 -144
  71. data/features/built_in_matchers/have.feature +0 -109
  72. data/features/built_in_matchers/include.feature +0 -174
  73. data/features/built_in_matchers/match.feature +0 -52
  74. data/features/built_in_matchers/operators.feature +0 -227
  75. data/features/built_in_matchers/predicates.feature +0 -137
  76. data/features/built_in_matchers/respond_to.feature +0 -84
  77. data/features/built_in_matchers/satisfy.feature +0 -33
  78. data/features/built_in_matchers/start_with.feature +0 -48
  79. data/features/built_in_matchers/throw_symbol.feature +0 -91
  80. data/features/built_in_matchers/types.feature +0 -116
  81. data/features/built_in_matchers/yield.feature +0 -161
  82. data/features/custom_matchers/access_running_example.feature +0 -53
  83. data/features/custom_matchers/define_diffable_matcher.feature +0 -27
  84. data/features/custom_matchers/define_matcher.feature +0 -368
  85. data/features/custom_matchers/define_matcher_outside_rspec.feature +0 -38
  86. data/features/custom_matchers/define_matcher_with_fluent_interface.feature +0 -24
  87. data/features/customized_message.feature +0 -22
  88. data/features/diffing.feature +0 -85
  89. data/features/implicit_docstrings.feature +0 -52
  90. data/features/step_definitions/additional_cli_steps.rb +0 -22
  91. data/features/support/env.rb +0 -14
  92. data/features/syntax_configuration.feature +0 -71
  93. data/features/test_frameworks/test_unit.feature +0 -44
  94. data/lib/rspec/expectations/deprecation.rb +0 -17
  95. data/lib/rspec/expectations/differ.rb +0 -133
  96. data/lib/rspec/expectations/errors.rb +0 -9
  97. data/lib/rspec/expectations/extensions/array.rb +0 -9
  98. data/lib/rspec/expectations/extensions/object.rb +0 -29
  99. data/lib/rspec/expectations/extensions.rb +0 -2
  100. data/lib/rspec/matchers/be_close.rb +0 -9
  101. data/lib/rspec/matchers/built_in/have.rb +0 -124
  102. data/lib/rspec/matchers/built_in/match_array.rb +0 -51
  103. data/lib/rspec/matchers/built_in/start_and_end_with.rb +0 -48
  104. data/lib/rspec/matchers/compatibility.rb +0 -14
  105. data/lib/rspec/matchers/configuration.rb +0 -108
  106. data/lib/rspec/matchers/extensions/instance_eval_with_args.rb +0 -39
  107. data/lib/rspec/matchers/matcher.rb +0 -300
  108. data/lib/rspec/matchers/method_missing.rb +0 -12
  109. data/lib/rspec/matchers/operator_matcher.rb +0 -109
  110. data/lib/rspec/matchers/pretty.rb +0 -70
  111. data/lib/rspec/matchers/test_unit_integration.rb +0 -11
  112. data/lib/rspec-expectations.rb +0 -1
  113. data/spec/rspec/expectations/differ_spec.rb +0 -192
  114. data/spec/rspec/expectations/expectation_target_spec.rb +0 -82
  115. data/spec/rspec/expectations/extensions/kernel_spec.rb +0 -67
  116. data/spec/rspec/expectations/fail_with_spec.rb +0 -114
  117. data/spec/rspec/expectations/handler_spec.rb +0 -227
  118. data/spec/rspec/expectations/syntax_spec.rb +0 -139
  119. data/spec/rspec/matchers/base_matcher_spec.rb +0 -62
  120. data/spec/rspec/matchers/be_close_spec.rb +0 -22
  121. data/spec/rspec/matchers/be_instance_of_spec.rb +0 -63
  122. data/spec/rspec/matchers/be_kind_of_spec.rb +0 -41
  123. data/spec/rspec/matchers/be_spec.rb +0 -516
  124. data/spec/rspec/matchers/be_within_spec.rb +0 -137
  125. data/spec/rspec/matchers/change_spec.rb +0 -553
  126. data/spec/rspec/matchers/configuration_spec.rb +0 -206
  127. data/spec/rspec/matchers/cover_spec.rb +0 -69
  128. data/spec/rspec/matchers/description_generation_spec.rb +0 -190
  129. data/spec/rspec/matchers/dsl_spec.rb +0 -57
  130. data/spec/rspec/matchers/eq_spec.rb +0 -60
  131. data/spec/rspec/matchers/eql_spec.rb +0 -41
  132. data/spec/rspec/matchers/equal_spec.rb +0 -78
  133. data/spec/rspec/matchers/exist_spec.rb +0 -124
  134. data/spec/rspec/matchers/has_spec.rb +0 -122
  135. data/spec/rspec/matchers/have_spec.rb +0 -455
  136. data/spec/rspec/matchers/include_matcher_integration_spec.rb +0 -30
  137. data/spec/rspec/matchers/include_spec.rb +0 -531
  138. data/spec/rspec/matchers/match_array_spec.rb +0 -194
  139. data/spec/rspec/matchers/match_spec.rb +0 -61
  140. data/spec/rspec/matchers/matcher_spec.rb +0 -471
  141. data/spec/rspec/matchers/matchers_spec.rb +0 -37
  142. data/spec/rspec/matchers/method_missing_spec.rb +0 -28
  143. data/spec/rspec/matchers/operator_matcher_spec.rb +0 -223
  144. data/spec/rspec/matchers/raise_error_spec.rb +0 -485
  145. data/spec/rspec/matchers/respond_to_spec.rb +0 -292
  146. data/spec/rspec/matchers/satisfy_spec.rb +0 -44
  147. data/spec/rspec/matchers/start_with_end_with_spec.rb +0 -186
  148. data/spec/rspec/matchers/throw_symbol_spec.rb +0 -116
  149. data/spec/rspec/matchers/yield_spec.rb +0 -514
  150. data/spec/spec_helper.rb +0 -54
  151. data/spec/support/classes.rb +0 -56
  152. data/spec/support/in_sub_process.rb +0 -38
  153. data/spec/support/matchers.rb +0 -22
  154. data/spec/support/ruby_version.rb +0 -10
  155. data/spec/support/shared_examples.rb +0 -13
@@ -1,44 +1,113 @@
1
+ RSpec::Support.require_rspec_support "method_signature_verifier"
2
+
1
3
  module RSpec
2
4
  module Matchers
3
5
  module BuiltIn
4
- class RespondTo
6
+ # @api private
7
+ # Provides the implementation for `respond_to`.
8
+ # Not intended to be instantiated directly.
9
+ class RespondTo < BaseMatcher
5
10
  def initialize(*names)
6
11
  @names = names
7
12
  @expected_arity = nil
13
+ @expected_keywords = []
14
+ @ignoring_method_signature_failure = false
15
+ @unlimited_arguments = nil
16
+ @arbitrary_keywords = nil
17
+ end
18
+
19
+ # @api public
20
+ # Specifies the number of expected arguments.
21
+ #
22
+ # @example
23
+ # expect(obj).to respond_to(:message).with(3).arguments
24
+ def with(n)
25
+ @expected_arity = n
26
+ self
27
+ end
28
+
29
+ # @api public
30
+ # Specifies keyword arguments, if any.
31
+ #
32
+ # @example
33
+ # expect(obj).to respond_to(:message).with_keywords(:color, :shape)
34
+ # @example with an expected number of arguments
35
+ # expect(obj).to respond_to(:message).with(3).arguments.and_keywords(:color, :shape)
36
+ def with_keywords(*keywords)
37
+ @expected_keywords = keywords
38
+ self
39
+ end
40
+ alias :and_keywords :with_keywords
41
+
42
+ # @api public
43
+ # Specifies that the method accepts any keyword, i.e. the method has
44
+ # a splatted keyword parameter of the form **kw_args.
45
+ #
46
+ # @example
47
+ # expect(obj).to respond_to(:message).with_any_keywords
48
+ def with_any_keywords
49
+ @arbitrary_keywords = true
50
+ self
8
51
  end
52
+ alias :and_any_keywords :with_any_keywords
9
53
 
54
+ # @api public
55
+ # Specifies that the number of arguments has no upper limit, i.e. the
56
+ # method has a splatted parameter of the form *args.
57
+ #
58
+ # @example
59
+ # expect(obj).to respond_to(:message).with_unlimited_arguments
60
+ def with_unlimited_arguments
61
+ @unlimited_arguments = true
62
+ self
63
+ end
64
+ alias :and_unlimited_arguments :with_unlimited_arguments
65
+
66
+ # @api public
67
+ # No-op. Intended to be used as syntactic sugar when using `with`.
68
+ #
69
+ # @example
70
+ # expect(obj).to respond_to(:message).with(3).arguments
71
+ def argument
72
+ self
73
+ end
74
+ alias :arguments :argument
75
+
76
+ # @private
10
77
  def matches?(actual)
11
78
  find_failing_method_names(actual, :reject).empty?
12
79
  end
13
- alias == matches?
14
80
 
81
+ # @private
15
82
  def does_not_match?(actual)
16
83
  find_failing_method_names(actual, :select).empty?
17
84
  end
18
85
 
19
- def failure_message_for_should
20
- "expected #{@actual.inspect} to respond to #{@failing_method_names.collect {|name| name.inspect }.join(', ')}#{with_arity}"
86
+ # @api private
87
+ # @return [String]
88
+ def failure_message
89
+ "expected #{actual_formatted} to respond to #{@failing_method_names.map { |name| description_of(name) }.join(', ')}#{with_arity}"
21
90
  end
22
91
 
23
- def failure_message_for_should_not
24
- failure_message_for_should.sub(/to respond to/, 'not to respond to')
92
+ # @api private
93
+ # @return [String]
94
+ def failure_message_when_negated
95
+ failure_message.sub(/to respond to/, 'not to respond to')
25
96
  end
26
97
 
98
+ # @api private
99
+ # @return [String]
27
100
  def description
28
101
  "respond to #{pp_names}#{with_arity}"
29
102
  end
30
103
 
31
- def with(n)
32
- @expected_arity = n
33
- self
34
- end
35
-
36
- def argument
37
- self
104
+ # @api private
105
+ # Used by other matchers to suppress a check
106
+ def ignoring_method_signature_failure!
107
+ @ignoring_method_signature_failure = true
38
108
  end
39
- alias :arguments :argument
40
109
 
41
- private
110
+ private
42
111
 
43
112
  def find_failing_method_names(actual, filter_method)
44
113
  @actual = actual
@@ -48,25 +117,82 @@ module RSpec
48
117
  end
49
118
 
50
119
  def matches_arity?(actual, name)
51
- return true unless @expected_arity
52
-
53
- actual_arity = actual.method(name).arity
54
- if actual_arity < 0
55
- # ~ inverts the one's complement and gives us the number of required args
56
- ~actual_arity <= @expected_arity
57
- else
58
- actual_arity == @expected_arity
59
- end
120
+ ArityCheck.new(@expected_arity, @expected_keywords, @arbitrary_keywords, @unlimited_arguments).matches?(actual, name)
121
+ rescue NameError
122
+ return true if @ignoring_method_signature_failure
123
+ raise ArgumentError, "The #{matcher_name} matcher requires that " \
124
+ "the actual object define the method(s) in " \
125
+ "order to check arity, but the method " \
126
+ "`#{name}` is not defined. Remove the arity " \
127
+ "check or define the method to continue."
60
128
  end
61
129
 
62
130
  def with_arity
63
- @expected_arity.nil?? "" :
64
- " with #{@expected_arity} argument#{@expected_arity == 1 ? '' : 's'}"
131
+ str = ''.dup
132
+ str << " with #{with_arity_string}" if @expected_arity
133
+ str << " #{str.length == 0 ? 'with' : 'and'} #{with_keywords_string}" if @expected_keywords && @expected_keywords.count > 0
134
+ str << " #{str.length == 0 ? 'with' : 'and'} unlimited arguments" if @unlimited_arguments
135
+ str << " #{str.length == 0 ? 'with' : 'and'} any keywords" if @arbitrary_keywords
136
+ str
137
+ end
138
+
139
+ def with_arity_string
140
+ "#{@expected_arity} argument#{@expected_arity == 1 ? '' : 's'}"
141
+ end
142
+
143
+ def with_keywords_string
144
+ kw_str = case @expected_keywords.count
145
+ when 1
146
+ @expected_keywords.first.inspect
147
+ when 2
148
+ @expected_keywords.map(&:inspect).join(' and ')
149
+ else
150
+ "#{@expected_keywords[0...-1].map(&:inspect).join(', ')}, and #{@expected_keywords.last.inspect}"
151
+ end
152
+
153
+ "keyword#{@expected_keywords.count == 1 ? '' : 's'} #{kw_str}"
65
154
  end
66
155
 
67
156
  def pp_names
68
- # Ruby 1.9 returns the same thing for array.to_s as array.inspect, so just use array.inspect here
69
- @names.length == 1 ? "##{@names.first}" : @names.inspect
157
+ @names.length == 1 ? "##{@names.first}" : description_of(@names)
158
+ end
159
+
160
+ # @private
161
+ class ArityCheck
162
+ def initialize(expected_arity, expected_keywords, arbitrary_keywords, unlimited_arguments)
163
+ expectation = Support::MethodSignatureExpectation.new
164
+
165
+ if expected_arity.is_a?(Range)
166
+ expectation.min_count = expected_arity.min
167
+ expectation.max_count = expected_arity.max
168
+ else
169
+ expectation.min_count = expected_arity
170
+ end
171
+
172
+ expectation.keywords = expected_keywords
173
+ expectation.expect_unlimited_arguments = unlimited_arguments
174
+ expectation.expect_arbitrary_keywords = arbitrary_keywords
175
+ @expectation = expectation
176
+ end
177
+
178
+ def matches?(actual, name)
179
+ return true if @expectation.empty?
180
+ verifier_for(actual, name).with_expectation(@expectation).valid?
181
+ end
182
+
183
+ def verifier_for(actual, name)
184
+ Support::StrictSignatureVerifier.new(method_signature_for(actual, name))
185
+ end
186
+
187
+ def method_signature_for(actual, name)
188
+ method_handle = Support.method_handle_for(actual, name)
189
+
190
+ if name == :new && method_handle.owner === ::Class && ::Class === actual
191
+ Support::MethodSignature.new(actual.instance_method(:initialize))
192
+ else
193
+ Support::MethodSignature.new(method_handle)
194
+ end
195
+ end
70
196
  end
71
197
  end
72
198
  end
@@ -1,28 +1,58 @@
1
1
  module RSpec
2
2
  module Matchers
3
3
  module BuiltIn
4
- class Satisfy
5
- def initialize(&block)
4
+ # @api private
5
+ # Provides the implementation for `satisfy`.
6
+ # Not intended to be instantiated directly.
7
+ class Satisfy < BaseMatcher
8
+ def initialize(description=nil, &block)
9
+ @description = description
6
10
  @block = block
7
11
  end
8
12
 
13
+ # @private
9
14
  def matches?(actual, &block)
10
15
  @block = block if block
11
16
  @actual = actual
12
17
  @block.call(actual)
13
18
  end
14
- alias == matches?
15
19
 
16
- def failure_message_for_should
17
- "expected #{@actual} to satisfy block"
20
+ # @private
21
+ def description
22
+ @description ||= "satisfy #{block_representation}"
18
23
  end
19
24
 
20
- def failure_message_for_should_not
21
- "expected #{@actual} not to satisfy block"
25
+ # @api private
26
+ # @return [String]
27
+ def failure_message
28
+ "expected #{actual_formatted} to #{description}"
22
29
  end
23
30
 
24
- def description
25
- "satisfy block"
31
+ # @api private
32
+ # @return [String]
33
+ def failure_message_when_negated
34
+ "expected #{actual_formatted} not to #{description}"
35
+ end
36
+
37
+ private
38
+
39
+ if RSpec::Support::RubyFeatures.ripper_supported?
40
+ def block_representation
41
+ if (block_snippet = extract_block_snippet)
42
+ "expression `#{block_snippet}`"
43
+ else
44
+ 'block'
45
+ end
46
+ end
47
+
48
+ def extract_block_snippet
49
+ return nil unless @block
50
+ Expectations::BlockSnippetExtractor.try_extracting_single_line_body_of(@block, matcher_name)
51
+ end
52
+ else
53
+ def block_representation
54
+ 'block'
55
+ end
26
56
  end
27
57
  end
28
58
  end
@@ -0,0 +1,94 @@
1
+ module RSpec
2
+ module Matchers
3
+ module BuiltIn
4
+ # @api private
5
+ # Base class for the `end_with` and `start_with` matchers.
6
+ # Not intended to be instantiated directly.
7
+ class StartOrEndWith < BaseMatcher
8
+ def initialize(*expected)
9
+ @actual_does_not_have_ordered_elements = false
10
+ @expected = expected.length == 1 ? expected.first : expected
11
+ end
12
+
13
+ # @api private
14
+ # @return [String]
15
+ def failure_message
16
+ super.tap do |msg|
17
+ if @actual_does_not_have_ordered_elements
18
+ msg << ", but it does not have ordered elements"
19
+ elsif !actual.respond_to?(:[])
20
+ msg << ", but it cannot be indexed using #[]"
21
+ end
22
+ end
23
+ end
24
+
25
+ # @api private
26
+ # @return [String]
27
+ def description
28
+ return super unless Hash === expected
29
+ english_name = EnglishPhrasing.split_words(self.class.matcher_name)
30
+ description_of_expected = surface_descriptions_in(expected).inspect
31
+ "#{english_name} #{description_of_expected}"
32
+ end
33
+
34
+ private
35
+
36
+ def match(_expected, actual)
37
+ return false unless actual.respond_to?(:[])
38
+
39
+ begin
40
+ return true if subsets_comparable? && subset_matches?
41
+ element_matches?
42
+ rescue ArgumentError
43
+ @actual_does_not_have_ordered_elements = true
44
+ return false
45
+ end
46
+ end
47
+
48
+ def subsets_comparable?
49
+ # Structs support the Enumerable interface but don't really have
50
+ # the semantics of a subset of a larger set...
51
+ return false if Struct === expected
52
+
53
+ expected.respond_to?(:length)
54
+ end
55
+ end
56
+
57
+ # For RSpec 3.1, the base class was named `StartAndEndWith`. For SemVer reasons,
58
+ # we still provide this constant until 4.0.
59
+ # @deprecated Use StartOrEndWith instead.
60
+ # @private
61
+ StartAndEndWith = StartOrEndWith
62
+
63
+ # @api private
64
+ # Provides the implementation for `start_with`.
65
+ # Not intended to be instantiated directly.
66
+ class StartWith < StartOrEndWith
67
+ private
68
+
69
+ def subset_matches?
70
+ values_match?(expected, actual[0, expected.length])
71
+ end
72
+
73
+ def element_matches?
74
+ values_match?(expected, actual[0])
75
+ end
76
+ end
77
+
78
+ # @api private
79
+ # Provides the implementation for `end_with`.
80
+ # Not intended to be instantiated directly.
81
+ class EndWith < StartOrEndWith
82
+ private
83
+
84
+ def subset_matches?
85
+ values_match?(expected, actual[-expected.length, expected.length])
86
+ end
87
+
88
+ def element_matches?
89
+ values_match?(expected, actual[-1])
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -1,14 +1,24 @@
1
1
  module RSpec
2
2
  module Matchers
3
3
  module BuiltIn
4
+ # @api private
5
+ # Provides the implementation for `throw_symbol`.
6
+ # Not intended to be instantiated directly.
4
7
  class ThrowSymbol
5
- def initialize(expected_symbol = nil, expected_arg=nil)
8
+ include Composable
9
+
10
+ def initialize(expected_symbol=nil, expected_arg=nil)
6
11
  @expected_symbol = expected_symbol
7
12
  @expected_arg = expected_arg
8
13
  @caught_symbol = @caught_arg = nil
9
14
  end
10
15
 
16
+ # rubocop:disable Metrics/MethodLength
17
+ # @private
11
18
  def matches?(given_proc)
19
+ @block = given_proc
20
+ return false unless Proc === given_proc
21
+
12
22
  begin
13
23
  if @expected_symbol.nil?
14
24
  given_proc.call
@@ -30,44 +40,78 @@ module RSpec
30
40
  # Ruby 1.8 uses NameError with `symbol'
31
41
  # Ruby 1.9 uses ArgumentError with :symbol
32
42
  rescue NameError, ArgumentError => e
33
- unless e.message =~ /uncaught throw (`|\:)([a-zA-Z0-9_]*)(')?/
43
+ unless (match_data = e.message.match(/uncaught throw (`|\:)([a-zA-Z0-9_]*)(')?/))
34
44
  other_exception = e
35
45
  raise
36
46
  end
37
- @caught_symbol = $2.to_sym
47
+ @caught_symbol = match_data.captures[1].to_sym
38
48
  rescue => other_exception
39
49
  raise
40
50
  ensure
51
+ # rubocop:disable Lint/EnsureReturn
41
52
  unless other_exception
42
53
  if @expected_symbol.nil?
43
- return !@caught_symbol.nil?
54
+ return !!@caught_symbol
44
55
  else
45
56
  if @expected_arg.nil?
46
57
  return @caught_symbol == @expected_symbol
47
58
  else
48
- return (@caught_symbol == @expected_symbol) & (@caught_arg == @expected_arg)
59
+ return (@caught_symbol == @expected_symbol) && values_match?(@expected_arg, @caught_arg)
49
60
  end
50
61
  end
51
62
  end
63
+ # rubocop:enable Lint/EnsureReturn
52
64
  end
53
65
  end
54
- alias == matches?
66
+ # rubocop:enable Metrics/MethodLength
67
+
68
+ def does_not_match?(given_proc)
69
+ !matches?(given_proc) && Proc === given_proc
70
+ end
55
71
 
56
- def failure_message_for_should
57
- "expected #{expected} to be thrown, got #{caught}"
72
+ # @api private
73
+ # @return [String]
74
+ def failure_message
75
+ "expected #{expected} to be thrown, #{actual_result}"
58
76
  end
59
77
 
60
- def failure_message_for_should_not
61
- "expected #{expected('no Symbol')}#{' not' if @expected_symbol} to be thrown, got #{caught}"
78
+ # @api private
79
+ # @return [String]
80
+ def failure_message_when_negated
81
+ "expected #{expected('no Symbol')}#{' not' if @expected_symbol} to be thrown, #{actual_result}"
62
82
  end
63
83
 
84
+ # @api private
85
+ # @return [String]
64
86
  def description
65
87
  "throw #{expected}"
66
88
  end
67
89
 
68
- private
90
+ # @api private
91
+ # Indicates this matcher matches against a block.
92
+ # @return [True]
93
+ def supports_block_expectations?
94
+ true
95
+ end
96
+
97
+ # @api private
98
+ def supports_value_expectations?
99
+ false
100
+ end
101
+
102
+ # @api private
103
+ def expects_call_stack_jump?
104
+ true
105
+ end
106
+
107
+ private
108
+
109
+ def actual_result
110
+ return "but was not a block" unless Proc === @block
111
+ "got #{caught}"
112
+ end
69
113
 
70
- def expected(symbol_desc = 'a Symbol')
114
+ def expected(symbol_desc='a Symbol')
71
115
  throw_description(@expected_symbol || symbol_desc, @expected_arg)
72
116
  end
73
117
 
@@ -76,10 +120,10 @@ module RSpec
76
120
  end
77
121
 
78
122
  def throw_description(symbol, arg)
79
- symbol_description = symbol.is_a?(String) ? symbol : symbol.inspect
123
+ symbol_description = symbol.is_a?(String) ? symbol : description_of(symbol)
80
124
 
81
125
  arg_description = if arg
82
- " with #{arg.inspect}"
126
+ " with #{description_of arg}"
83
127
  elsif @expected_arg && @caught_symbol == @expected_symbol
84
128
  " with no argument"
85
129
  else