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,29 +1,24 @@
1
- require 'rspec/matchers/extensions/instance_eval_with_args'
2
- require 'rspec/matchers/pretty'
1
+ require 'rspec/support'
2
+ RSpec::Support.require_rspec_support 'matcher_definition'
3
+ RSpec::Support.define_optimized_require_for_rspec(:matchers) { |f| require_relative(f) }
3
4
 
4
- require 'rspec/matchers/built_in'
5
- require 'rspec/matchers/matcher'
6
- require 'rspec/matchers/operator_matcher'
7
- require 'rspec/matchers/be_close'
8
-
9
- require 'rspec/matchers/generated_descriptions'
10
- require 'rspec/matchers/method_missing'
11
- require 'rspec/matchers/compatibility'
12
- require 'rspec/matchers/dsl'
13
- require 'rspec/matchers/test_unit_integration'
5
+ %w[
6
+ english_phrasing
7
+ composable
8
+ built_in
9
+ generated_descriptions
10
+ dsl
11
+ matcher_delegator
12
+ aliased_matcher
13
+ multi_matcher_diff
14
+ ].each { |file| RSpec::Support.require_rspec_matchers(file) }
14
15
 
16
+ # RSpec's top level namespace. All of rspec-expectations is contained
17
+ # in the `RSpec::Expectations` and `RSpec::Matchers` namespaces.
15
18
  module RSpec
16
19
  # RSpec::Matchers provides a number of useful matchers we use to define
17
- # expectations. A matcher is any object that responds to the following:
18
- #
19
- # matches?(actual)
20
- # failure_message_for_should
21
- #
22
- # These methods are also part of the matcher protocol, but are optional:
23
- #
24
- # does_not_match?(actual)
25
- # failure_message_for_should_not
26
- # description
20
+ # expectations. Any object that implements the [matcher protocol](Matchers/MatcherProtocol)
21
+ # can be used as a matcher.
27
22
  #
28
23
  # ## Predicates
29
24
  #
@@ -41,14 +36,14 @@ module RSpec
41
36
  # expect([]).to be_empty # => [].empty?() | passes
42
37
  # expect([]).not_to be_empty # => [].empty?() | fails
43
38
  #
44
- # In addtion to prefixing the predicate matchers with "be_", you can also use "be_a_"
39
+ # In addition to prefixing the predicate matchers with "be_", you can also use "be_a_"
45
40
  # and "be_an_", making your specs read much more naturally:
46
41
  #
47
42
  # expect("a string").to be_an_instance_of(String) # =>"a string".instance_of?(String) # passes
48
43
  #
49
- # expect(3).to be_a_kind_of(Fixnum) # => 3.kind_of?(Numeric) | passes
50
- # expect(3).to be_a_kind_of(Numeric) # => 3.kind_of?(Numeric) | passes
51
- # expect(3).to be_an_instance_of(Fixnum) # => 3.instance_of?(Fixnum) | passes
44
+ # expect(3).to be_a_kind_of(Integer) # => 3.kind_of?(Numeric) | passes
45
+ # expect(3).to be_a_kind_of(Numeric) # => 3.kind_of?(Numeric) | passes
46
+ # expect(3).to be_an_instance_of(Integer) # => 3.instance_of?(Integer) | passes
52
47
  # expect(3).not_to be_an_instance_of(Numeric) # => 3.instance_of?(Numeric) | fails
53
48
  #
54
49
  # RSpec will also create custom matchers for predicates like `has_key?`. To
@@ -61,6 +56,32 @@ module RSpec
61
56
  # You can use this feature to invoke any predicate that begins with "has_", whether it is
62
57
  # part of the Ruby libraries (like `Hash#has_key?`) or a method you wrote on your own class.
63
58
  #
59
+ # Note that RSpec does not provide composable aliases for these dynamic predicate
60
+ # matchers. You can easily define your own aliases, though:
61
+ #
62
+ # RSpec::Matchers.alias_matcher :a_user_who_is_an_admin, :be_an_admin
63
+ # expect(user_list).to include(a_user_who_is_an_admin)
64
+ #
65
+ # ## Alias Matchers
66
+ #
67
+ # With {RSpec::Matchers.alias_matcher}, you can easily create an
68
+ # alternate name for a given matcher.
69
+ #
70
+ # The description will also change according to the new name:
71
+ #
72
+ # RSpec::Matchers.alias_matcher :a_list_that_sums_to, :sum_to
73
+ # sum_to(3).description # => "sum to 3"
74
+ # a_list_that_sums_to(3).description # => "a list that sums to 3"
75
+ #
76
+ # or you can specify a custom description like this:
77
+ #
78
+ # RSpec::Matchers.alias_matcher :a_list_sorted_by, :be_sorted_by do |description|
79
+ # description.sub("be sorted by", "a list sorted by")
80
+ # end
81
+ #
82
+ # be_sorted_by(:age).description # => "be sorted by age"
83
+ # a_list_sorted_by(:age).description # => "a list sorted by age"
84
+ #
64
85
  # ## Custom Matchers
65
86
  #
66
87
  # When you find that none of the stock matchers provide a natural feeling
@@ -100,11 +121,11 @@ module RSpec
100
121
  # player.in_zone?(zone)
101
122
  # end
102
123
  #
103
- # failure_message_for_should do |player|
124
+ # failure_message do |player|
104
125
  # # generate and return the appropriate string.
105
126
  # end
106
127
  #
107
- # failure_message_for_should_not do |player|
128
+ # failure_message_when_negated do |player|
108
129
  # # generate and return the appropriate string.
109
130
  # end
110
131
  #
@@ -115,8 +136,8 @@ module RSpec
115
136
  #
116
137
  # Each of the message-generation methods has access to the block arguments
117
138
  # passed to the <tt>create</tt> method (in this case, <tt>zone</tt>). The
118
- # failure message methods (<tt>failure_message_for_should</tt> and
119
- # <tt>failure_message_for_should_not</tt>) are passed the actual value (the
139
+ # failure message methods (<tt>failure_message</tt> and
140
+ # <tt>failure_message_when_negated</tt>) are passed the actual value (the
120
141
  # receiver of <tt>expect(..)</tt> or <tt>expect(..).not_to</tt>).
121
142
  #
122
143
  # ### Custom Matcher from scratch
@@ -133,11 +154,11 @@ module RSpec
133
154
  # @target.current_zone.eql?(Zone.new(@expected))
134
155
  # end
135
156
  #
136
- # def failure_message_for_should
157
+ # def failure_message
137
158
  # "expected #{@target.inspect} to be in Zone #{@expected}"
138
159
  # end
139
160
  #
140
- # def failure_message_for_should_not
161
+ # def failure_message_when_negated
141
162
  # "expected #{@target.inspect} not to be in Zone #{@expected}"
142
163
  # end
143
164
  # end
@@ -173,34 +194,141 @@ module RSpec
173
194
  # RSpec::configure do |config|
174
195
  # config.include(CustomGameMatchers)
175
196
  # end
176
- module Matchers
177
- # @api private
178
- def self.is_a_matcher?(obj)
179
- return true if ::RSpec::Matchers::BuiltIn::BaseMatcher === obj
180
- return false if obj.respond_to?(:i_respond_to_everything_so_im_not_really_a_matcher)
181
- return false unless obj.respond_to?(:matches?)
197
+ #
198
+ # ### Making custom matchers composable
199
+ #
200
+ # RSpec's built-in matchers are designed to be composed, in expressions like:
201
+ #
202
+ # expect(["barn", 2.45]).to contain_exactly(
203
+ # a_value_within(0.1).of(2.5),
204
+ # a_string_starting_with("bar")
205
+ # )
206
+ #
207
+ # Custom matchers can easily participate in composed matcher expressions like these.
208
+ # Include {RSpec::Matchers::Composable} in your custom matcher to make it support
209
+ # being composed (matchers defined using the DSL have this included automatically).
210
+ # Within your matcher's `matches?` method (or the `match` block, if using the DSL),
211
+ # use `values_match?(expected, actual)` rather than `expected == actual`.
212
+ # Under the covers, `values_match?` is able to match arbitrary
213
+ # nested data structures containing a mix of both matchers and non-matcher objects.
214
+ # It uses `===` and `==` to perform the matching, considering the values to
215
+ # match if either returns `true`. The `Composable` mixin also provides some helper
216
+ # methods for surfacing the matcher descriptions within your matcher's description
217
+ # or failure messages.
218
+ #
219
+ # RSpec's built-in matchers each have a number of aliases that rephrase the matcher
220
+ # from a verb phrase (such as `be_within`) to a noun phrase (such as `a_value_within`),
221
+ # which reads better when the matcher is passed as an argument in a composed matcher
222
+ # expressions, and also uses the noun-phrase wording in the matcher's `description`,
223
+ # for readable failure messages. You can alias your custom matchers in similar fashion
224
+ # using {RSpec::Matchers.alias_matcher}.
225
+ #
226
+ # ## Negated Matchers
227
+ #
228
+ # Sometimes if you want to test for the opposite using a more descriptive name
229
+ # instead of using `not_to`, you can use {RSpec::Matchers.define_negated_matcher}:
230
+ #
231
+ # RSpec::Matchers.define_negated_matcher :exclude, :include
232
+ # include(1, 2).description # => "include 1 and 2"
233
+ # exclude(1, 2).description # => "exclude 1 and 2"
234
+ #
235
+ # While the most obvious negated form may be to add a `not_` prefix,
236
+ # the failure messages you get with that form can be confusing (e.g.
237
+ # "expected [actual] to not [verb], but did not"). We've found it works
238
+ # best to find a more positive name for the negated form, such as
239
+ # `avoid_changing` rather than `not_change`.
240
+ #
241
+ module Matchers # rubocop:disable Metrics/ModuleLength
242
+ extend ::RSpec::Matchers::DSL
243
+
244
+ # @!macro [attach] alias_matcher
245
+ # @!parse
246
+ # alias $1 $2
247
+ # @!visibility private
248
+ # We define this override here so we can attach a YARD macro to it.
249
+ # It ensures that our docs list all the matcher aliases.
250
+ def self.alias_matcher(*args, &block)
251
+ super(*args, &block)
252
+ end
253
+
254
+ # @!method self.alias_matcher(new_name, old_name, options={}, &description_override)
255
+ # Extended from {RSpec::Matchers::DSL#alias_matcher}.
182
256
 
183
- obj.respond_to?(:failure_message_for_should) || obj.respond_to?(:failure_message)
257
+ # @!method self.define(name, &declarations)
258
+ # Extended from {RSpec::Matchers::DSL#define}.
259
+
260
+ # @!method self.define_negated_matcher(negated_name, base_name, &description_override)
261
+ # Extended from {RSpec::Matchers::DSL#define_negated_matcher}.
262
+
263
+ # @method expect
264
+ # Supports `expect(actual).to matcher` syntax by wrapping `actual` in an
265
+ # `ExpectationTarget`.
266
+ # @example
267
+ # expect(actual).to eq(expected)
268
+ # expect(actual).not_to eq(expected)
269
+ # @return [Expectations::ExpectationTarget]
270
+ # @see Expectations::ExpectationTarget#to
271
+ # @see Expectations::ExpectationTarget#not_to
272
+
273
+ # Allows multiple expectations in the provided block to fail, and then
274
+ # aggregates them into a single exception, rather than aborting on the
275
+ # first expectation failure like normal. This allows you to see all
276
+ # failures from an entire set of expectations without splitting each
277
+ # off into its own example (which may slow things down if the example
278
+ # setup is expensive).
279
+ #
280
+ # @param label [String] label for this aggregation block, which will be
281
+ # included in the aggregated exception message.
282
+ # @param metadata [Hash] additional metadata about this failure aggregation
283
+ # block. If multiple expectations fail, it will be exposed from the
284
+ # {Expectations::MultipleExpectationsNotMetError} exception. Mostly
285
+ # intended for internal RSpec use but you can use it as well.
286
+ # @yield Block containing as many expectation as you want. The block is
287
+ # simply yielded to, so you can trust that anything that works outside
288
+ # the block should work within it.
289
+ # @raise [Expectations::MultipleExpectationsNotMetError] raised when
290
+ # multiple expectations fail.
291
+ # @raise [Expectations::ExpectationNotMetError] raised when a single
292
+ # expectation fails.
293
+ # @raise [Exception] other sorts of exceptions will be raised as normal.
294
+ #
295
+ # @example
296
+ # aggregate_failures("verifying response") do
297
+ # expect(response.status).to eq(200)
298
+ # expect(response.headers).to include("Content-Type" => "text/plain")
299
+ # expect(response.body).to include("Success")
300
+ # end
301
+ #
302
+ # @note The implementation of this feature uses a thread-local variable,
303
+ # which means that if you have an expectation failure in another thread,
304
+ # it'll abort like normal.
305
+ def aggregate_failures(label=nil, metadata={}, &block)
306
+ Expectations::FailureAggregator.new(label, metadata).aggregate(&block)
184
307
  end
185
308
 
186
309
  # Passes if actual is truthy (anything but false or nil)
187
- def be_true
188
- BuiltIn::BeTrue.new
310
+ def be_truthy
311
+ BuiltIn::BeTruthy.new
189
312
  end
313
+ alias_matcher :a_truthy_value, :be_truthy
190
314
 
191
- # Passes if actual is falsy (false or nil)
192
- def be_false
193
- BuiltIn::BeFalse.new
315
+ # Passes if actual is falsey (false or nil)
316
+ def be_falsey
317
+ BuiltIn::BeFalsey.new
194
318
  end
319
+ alias_matcher :be_falsy, :be_falsey
320
+ alias_matcher :a_falsey_value, :be_falsey
321
+ alias_matcher :a_falsy_value, :be_falsey
195
322
 
196
323
  # Passes if actual is nil
197
324
  def be_nil
198
325
  BuiltIn::BeNil.new
199
326
  end
327
+ alias_matcher :a_nil_value, :be_nil
200
328
 
201
329
  # @example
202
- # expect(actual).to be_true
203
- # expect(actual).to be_false
330
+ # expect(actual).to be_truthy
331
+ # expect(actual).to be_falsey
204
332
  # expect(actual).to be_nil
205
333
  # expect(actual).to be_[arbitrary_predicate](*args)
206
334
  # expect(actual).not_to be_nil
@@ -219,52 +347,66 @@ module RSpec
219
347
  # (e.g. be_empty), letting you choose the prefix that best suits the
220
348
  # predicate.
221
349
  def be(*args)
222
- args.empty? ?
223
- Matchers::BuiltIn::Be.new : equal(*args)
350
+ args.empty? ? Matchers::BuiltIn::Be.new : equal(*args)
224
351
  end
352
+ alias_matcher :a_value, :be, :klass => AliasedMatcherWithOperatorSupport
225
353
 
226
354
  # passes if target.kind_of?(klass)
227
355
  def be_a(klass)
228
356
  be_a_kind_of(klass)
229
357
  end
230
-
231
358
  alias_method :be_an, :be_a
232
359
 
233
360
  # Passes if actual.instance_of?(expected)
234
361
  #
235
362
  # @example
236
- #
237
- # expect(5).to be_an_instance_of(Fixnum)
363
+ # expect(5).to be_an_instance_of(Integer)
238
364
  # expect(5).not_to be_an_instance_of(Numeric)
239
365
  # expect(5).not_to be_an_instance_of(Float)
240
366
  def be_an_instance_of(expected)
241
367
  BuiltIn::BeAnInstanceOf.new(expected)
242
368
  end
243
-
244
369
  alias_method :be_instance_of, :be_an_instance_of
370
+ alias_matcher :an_instance_of, :be_an_instance_of
245
371
 
246
372
  # Passes if actual.kind_of?(expected)
247
373
  #
248
374
  # @example
249
- #
250
- # expect(5).to be_a_kind_of(Fixnum)
375
+ # expect(5).to be_a_kind_of(Integer)
251
376
  # expect(5).to be_a_kind_of(Numeric)
252
377
  # expect(5).not_to be_a_kind_of(Float)
253
378
  def be_a_kind_of(expected)
254
379
  BuiltIn::BeAKindOf.new(expected)
255
380
  end
256
-
257
381
  alias_method :be_kind_of, :be_a_kind_of
382
+ alias_matcher :a_kind_of, :be_a_kind_of
258
383
 
259
- # Passes if actual == expected +/- delta
384
+ # Passes if actual.between?(min, max). Works with any Comparable object,
385
+ # including String, Symbol, Time, or Numeric (Fixnum, Bignum, Integer,
386
+ # Float, Complex, and Rational).
387
+ #
388
+ # By default, `be_between` is inclusive (i.e. passes when given either the max or min value),
389
+ # but you can make it `exclusive` by chaining that off the matcher.
260
390
  #
261
391
  # @example
392
+ # expect(5).to be_between(1, 10)
393
+ # expect(11).not_to be_between(1, 10)
394
+ # expect(10).not_to be_between(1, 10).exclusive
395
+ def be_between(min, max)
396
+ BuiltIn::BeBetween.new(min, max)
397
+ end
398
+ alias_matcher :a_value_between, :be_between
399
+
400
+ # Passes if actual == expected +/- delta
262
401
  #
402
+ # @example
263
403
  # expect(result).to be_within(0.5).of(3.0)
264
404
  # expect(result).not_to be_within(0.5).of(3.0)
265
405
  def be_within(delta)
266
406
  BuiltIn::BeWithin.new(delta)
267
407
  end
408
+ alias_matcher :a_value_within, :be_within
409
+ alias_matcher :within, :be_within
268
410
 
269
411
  # Applied to a proc, specifies that its execution will cause some value to
270
412
  # change.
@@ -275,12 +417,23 @@ module RSpec
275
417
  # You can either pass <tt>receiver</tt> and <tt>message</tt>, or a block,
276
418
  # but not both.
277
419
  #
278
- # When passing a block, it must use the <tt>{ ... }</tt> format, not
279
- # do/end, as <tt>{ ... }</tt> binds to the +change+ method, whereas do/end
280
- # would errantly bind to the +expect(..)+ or +expect(..).not_to+ method.
420
+ # When passing a block, it must use the `{ ... }` format, not
421
+ # do/end, as `{ ... }` binds to the `change` method, whereas do/end
422
+ # would errantly bind to the `expect(..).to` or `expect(...).not_to` method.
281
423
  #
282
- # @example
424
+ # You can chain any of the following off of the end to specify details
425
+ # about the change:
426
+ #
427
+ # * `from`
428
+ # * `to`
429
+ #
430
+ # or any one of:
431
+ #
432
+ # * `by`
433
+ # * `by_at_least`
434
+ # * `by_at_most`
283
435
  #
436
+ # @example
284
437
  # expect {
285
438
  # team.add_player(player)
286
439
  # }.to change(roster, :count)
@@ -305,7 +458,7 @@ module RSpec
305
458
  # string = "string"
306
459
  # expect {
307
460
  # string
308
- # }.not_to change { string }
461
+ # }.not_to change { string }.from("string")
309
462
  #
310
463
  # expect {
311
464
  # person.happy_birthday
@@ -326,15 +479,39 @@ module RSpec
326
479
  #
327
480
  # == Notes
328
481
  #
329
- # Evaluates <tt>receiver.message</tt> or <tt>block</tt> before and after it
330
- # evaluates the block passed to <tt>expect</tt>.
482
+ # Evaluates `receiver.message` or `block` before and after it
483
+ # evaluates the block passed to `expect`. If the value is the same
484
+ # object, its before/after `hash` value is used to see if it has changed.
485
+ # Therefore, your object needs to properly implement `hash` to work correctly
486
+ # with this matcher.
331
487
  #
332
- # <tt>expect( ... ).not_to change</tt> only supports the form with no subsequent
333
- # calls to <tt>by</tt>, <tt>by_at_least</tt>, <tt>by_at_most</tt>,
334
- # <tt>to</tt> or <tt>from</tt>.
488
+ # `expect( ... ).not_to change` supports the form that specifies `from`
489
+ # (which specifies what you expect the starting, unchanged value to be)
490
+ # but does not support forms with subsequent calls to `by`, `by_at_least`,
491
+ # `by_at_most` or `to`.
335
492
  def change(receiver=nil, message=nil, &block)
336
493
  BuiltIn::Change.new(receiver, message, &block)
337
494
  end
495
+ alias_matcher :a_block_changing, :change
496
+ alias_matcher :changing, :change
497
+
498
+ # Passes if actual contains all of the expected regardless of order.
499
+ # This works for collections. Pass in multiple args and it will only
500
+ # pass if all args are found in collection.
501
+ #
502
+ # @note This is also available using the `=~` operator with `should`,
503
+ # but `=~` is not supported with `expect`.
504
+ #
505
+ # @example
506
+ # expect([1, 2, 3]).to contain_exactly(1, 2, 3)
507
+ # expect([1, 2, 3]).to contain_exactly(1, 3, 2)
508
+ #
509
+ # @see #match_array
510
+ def contain_exactly(*items)
511
+ BuiltIn::ContainExactly.new(items)
512
+ end
513
+ alias_matcher :a_collection_containing_exactly, :contain_exactly
514
+ alias_matcher :containing_exactly, :contain_exactly
338
515
 
339
516
  # Passes if actual covers expected. This works for
340
517
  # Ranges. You can also pass in multiple args
@@ -350,7 +527,9 @@ module RSpec
350
527
  # ### Warning:: Ruby >= 1.9 only
351
528
  def cover(*values)
352
529
  BuiltIn::Cover.new(*values)
353
- end if (1..2).respond_to?(:cover?)
530
+ end
531
+ alias_matcher :a_range_covering, :cover
532
+ alias_matcher :covering, :cover
354
533
 
355
534
  # Matches if the actual value ends with the expected value(s). In the case
356
535
  # of a string, matches against the last `expected.length` characters of the
@@ -358,13 +537,15 @@ module RSpec
358
537
  # `expected.length` elements of the actual array.
359
538
  #
360
539
  # @example
361
- #
362
540
  # expect("this string").to end_with "string"
363
541
  # expect([0, 1, 2, 3, 4]).to end_with 4
364
542
  # expect([0, 2, 3, 4, 4]).to end_with 3, 4
365
543
  def end_with(*expected)
366
544
  BuiltIn::EndWith.new(*expected)
367
545
  end
546
+ alias_matcher :a_collection_ending_with, :end_with
547
+ alias_matcher :a_string_ending_with, :end_with
548
+ alias_matcher :ending_with, :end_with
368
549
 
369
550
  # Passes if <tt>actual == expected</tt>.
370
551
  #
@@ -372,25 +553,27 @@ module RSpec
372
553
  # information about equality in Ruby.
373
554
  #
374
555
  # @example
375
- #
376
556
  # expect(5).to eq(5)
377
557
  # expect(5).not_to eq(3)
378
558
  def eq(expected)
379
559
  BuiltIn::Eq.new(expected)
380
560
  end
561
+ alias_matcher :an_object_eq_to, :eq
562
+ alias_matcher :eq_to, :eq
381
563
 
382
- # Passes if +actual.eql?(expected)+
564
+ # Passes if `actual.eql?(expected)`
383
565
  #
384
566
  # See http://www.ruby-doc.org/core/classes/Object.html#M001057 for more
385
567
  # information about equality in Ruby.
386
568
  #
387
569
  # @example
388
- #
389
570
  # expect(5).to eql(5)
390
571
  # expect(5).not_to eql(3)
391
572
  def eql(expected)
392
573
  BuiltIn::Eql.new(expected)
393
574
  end
575
+ alias_matcher :an_object_eql_to, :eql
576
+ alias_matcher :eql_to, :eql
394
577
 
395
578
  # Passes if <tt>actual.equal?(expected)</tt> (object identity).
396
579
  #
@@ -398,12 +581,13 @@ module RSpec
398
581
  # information about equality in Ruby.
399
582
  #
400
583
  # @example
401
- #
402
- # expect(5).to equal(5) # Fixnums are equal
584
+ # expect(5).to equal(5) # Integers are equal
403
585
  # expect("5").not_to equal("5") # Strings that look the same are not the same object
404
586
  def equal(expected)
405
587
  BuiltIn::Equal.new(expected)
406
588
  end
589
+ alias_matcher :an_object_equal_to, :equal
590
+ alias_matcher :equal_to, :equal
407
591
 
408
592
  # Passes if `actual.exist?` or `actual.exists?`
409
593
  #
@@ -412,134 +596,204 @@ module RSpec
412
596
  def exist(*args)
413
597
  BuiltIn::Exist.new(*args)
414
598
  end
599
+ alias_matcher :an_object_existing, :exist
600
+ alias_matcher :existing, :exist
415
601
 
416
- # Passes if receiver is a collection with the submitted number of items OR
417
- # if the receiver OWNS a collection with the submitted number of items.
418
- #
419
- # If the receiver OWNS the collection, you must use the name of the
420
- # collection. So if a `Team` instance has a collection named `#players`,
421
- # you must use that name to set the expectation.
422
- #
423
- # If the receiver IS the collection, you can use any name you like for
424
- # `named_collection`. We'd recommend using either "elements", "members", or
425
- # "items" as these are all standard ways of describing the things IN a
426
- # collection.
427
- #
428
- # This also works for Strings, letting you set expectations about their
429
- # lengths.
602
+ # Passes if actual's attribute values match the expected attributes hash.
603
+ # This works no matter how you define your attribute readers.
430
604
  #
431
605
  # @example
606
+ # Person = Struct.new(:name, :age)
607
+ # person = Person.new("Bob", 32)
432
608
  #
433
- # # Passes if team.players.size == 11
434
- # expect(team).to have(11).players
609
+ # expect(person).to have_attributes(:name => "Bob", :age => 32)
610
+ # expect(person).to have_attributes(:name => a_string_starting_with("B"), :age => (a_value > 30) )
435
611
  #
436
- # # Passes if [1,2,3].length == 3
437
- # expect([1,2,3]).to have(3).items #"items" is pure sugar
438
- #
439
- # # Passes if ['a', 'b', 'c'].count == 3
440
- # expect([1,2,3]).to have(3).items #"items" is pure sugar
441
- #
442
- # # Passes if "this string".length == 11
443
- # expect("this string").to have(11).characters #"characters" is pure sugar
444
- def have(n)
445
- BuiltIn::Have.new(n)
446
- end
447
- alias :have_exactly :have
448
-
449
- # Exactly like have() with >=.
612
+ # @note It will fail if actual doesn't respond to any of the expected attributes.
450
613
  #
451
614
  # @example
452
- # expect("this").to have_at_least(3).letters
453
- #
454
- # ### Warning:
455
- #
456
- # `expect(..).not_to have_at_least` is not supported
457
- def have_at_least(n)
458
- BuiltIn::Have.new(n, :at_least)
459
- end
460
-
461
- # Exactly like have() with <=.
462
- #
463
- # @example
464
- # expect("this").to have_at_most(4).letters
465
- #
466
- # ### Warning:
467
- #
468
- # `expect(..).not_to have_at_most` is not supported
469
- def have_at_most(n)
470
- BuiltIn::Have.new(n, :at_most)
615
+ # expect(person).to have_attributes(:color => "red")
616
+ def have_attributes(expected)
617
+ BuiltIn::HaveAttributes.new(expected)
471
618
  end
619
+ alias_matcher :an_object_having_attributes, :have_attributes
620
+ alias_matcher :having_attributes, :have_attributes
472
621
 
473
622
  # Passes if actual includes expected. This works for
474
623
  # collections and Strings. You can also pass in multiple args
475
624
  # and it will only pass if all args are found in collection.
476
625
  #
477
626
  # @example
478
- #
479
627
  # expect([1,2,3]).to include(3)
480
628
  # expect([1,2,3]).to include(2,3)
481
629
  # expect([1,2,3]).to include(2,3,4) # fails
482
630
  # expect([1,2,3]).not_to include(4)
483
631
  # expect("spread").to include("read")
484
632
  # expect("spread").not_to include("red")
633
+ # expect(:a => 1, :b => 2).to include(:a)
634
+ # expect(:a => 1, :b => 2).to include(:a, :b)
635
+ # expect(:a => 1, :b => 2).to include(:a => 1)
636
+ # expect(:a => 1, :b => 2).to include(:b => 2, :a => 1)
637
+ # expect(:a => 1, :b => 2).to include(:c) # fails
638
+ # expect(:a => 1, :b => 2).not_to include(:a => 2)
485
639
  def include(*expected)
486
640
  BuiltIn::Include.new(*expected)
487
641
  end
642
+ alias_matcher :a_collection_including, :include
643
+ alias_matcher :a_string_including, :include
644
+ alias_matcher :a_hash_including, :include
645
+ alias_matcher :including, :include
488
646
 
489
- # Given a Regexp or String, passes if actual.match(pattern)
647
+ # Passes if the provided matcher passes when checked against all
648
+ # elements of the collection.
490
649
  #
491
650
  # @example
651
+ # expect([1, 3, 5]).to all be_odd
652
+ # expect([1, 3, 6]).to all be_odd # fails
492
653
  #
493
- # expect(email).to match(/^([^\s]+)((?:[-a-z0-9]+\.)+[a-z]{2,})$/i)
494
- # expect(email).to match("@example.com")
495
- # expect(zipcode).to match_regex(/\A\d{5}(-\d{4})?\z/)
496
- # expect(zipcode).to match_regex("90210")
654
+ # @note The negative form `not_to all` is not supported. Instead
655
+ # use `not_to include` or pass a negative form of a matcher
656
+ # as the argument (e.g. `all exclude(:foo)`).
497
657
  #
498
- # @note Due to Ruby's method dispatch mechanism, using the `#match` matcher
499
- # within a custom matcher defined via the matcher DSL
500
- # (`RSpec::Matcher.define`) will result Ruby calling the wrong `#match`
501
- # method and raising an `ArgumentError`. Instead, use the aliased
502
- # `#match_regex` method.
658
+ # @note You can also use this with compound matchers as well.
659
+ #
660
+ # @example
661
+ # expect([1, 3, 5]).to all( be_odd.and be_an(Integer) )
662
+ def all(expected)
663
+ BuiltIn::All.new(expected)
664
+ end
665
+
666
+ # Given a `Regexp` or `String`, passes if `actual.match(pattern)`
667
+ # Given an arbitrary nested data structure (e.g. arrays and hashes),
668
+ # matches if `expected === actual` || `actual == expected` for each
669
+ # pair of elements.
670
+ #
671
+ # @example
672
+ # expect(email).to match(/^([^\s]+)((?:[-a-z0-9]+\.)+[a-z]{2,})$/i)
673
+ # expect(email).to match("@example.com")
674
+ #
675
+ # @example
676
+ # hash = {
677
+ # :a => {
678
+ # :b => ["foo", 5],
679
+ # :c => { :d => 2.05 }
680
+ # }
681
+ # }
682
+ #
683
+ # expect(hash).to match(
684
+ # :a => {
685
+ # :b => a_collection_containing_exactly(
686
+ # a_string_starting_with("f"),
687
+ # an_instance_of(Integer)
688
+ # ),
689
+ # :c => { :d => (a_value < 3) }
690
+ # }
691
+ # )
692
+ #
693
+ # @note The `match_regex` alias is deprecated and is not recommended for use.
694
+ # It was added in 2.12.1 to facilitate its use from within custom
695
+ # matchers (due to how the custom matcher DSL was evaluated in 2.x,
696
+ # `match` could not be used there), but is no longer needed in 3.x.
503
697
  def match(expected)
504
698
  BuiltIn::Match.new(expected)
505
699
  end
700
+ alias_matcher :match_regex, :match
701
+ alias_matcher :an_object_matching, :match
702
+ alias_matcher :a_string_matching, :match
703
+ alias_matcher :matching, :match
506
704
 
507
- alias_method :match_regex, :match
705
+ # An alternate form of `contain_exactly` that accepts
706
+ # the expected contents as a single array arg rather
707
+ # than splatted out as individual items.
708
+ #
709
+ # @example
710
+ # expect(results).to contain_exactly(1, 2)
711
+ # # is identical to:
712
+ # expect(results).to match_array([1, 2])
713
+ #
714
+ # @see #contain_exactly
715
+ def match_array(items)
716
+ contain_exactly(*items)
717
+ end
718
+ alias_matcher :an_array_matching, :match_array do |desc|
719
+ desc.sub("contain exactly", "an array containing exactly")
720
+ end
721
+
722
+ # With no arg, passes if the block outputs `to_stdout` or `to_stderr`.
723
+ # With a string, passes if the block outputs that specific string `to_stdout` or `to_stderr`.
724
+ # With a regexp or matcher, passes if the block outputs a string `to_stdout` or `to_stderr` that matches.
725
+ #
726
+ # To capture output from any spawned subprocess as well, use `to_stdout_from_any_process` or
727
+ # `to_stderr_from_any_process`. Output from any process that inherits the main process's corresponding
728
+ # standard stream will be captured.
729
+ #
730
+ # @example
731
+ # expect { print 'foo' }.to output.to_stdout
732
+ # expect { print 'foo' }.to output('foo').to_stdout
733
+ # expect { print 'foo' }.to output(/foo/).to_stdout
734
+ #
735
+ # expect { do_something }.to_not output.to_stdout
736
+ #
737
+ # expect { warn('foo') }.to output.to_stderr
738
+ # expect { warn('foo') }.to output('foo').to_stderr
739
+ # expect { warn('foo') }.to output(/foo/).to_stderr
740
+ #
741
+ # expect { do_something }.to_not output.to_stderr
742
+ #
743
+ # expect { system('echo foo') }.to output("foo\n").to_stdout_from_any_process
744
+ # expect { system('echo foo', out: :err) }.to output("foo\n").to_stderr_from_any_process
745
+ #
746
+ # @note `to_stdout` and `to_stderr` work by temporarily replacing `$stdout` or `$stderr`,
747
+ # so they're not able to intercept stream output that explicitly uses `STDOUT`/`STDERR`
748
+ # or that uses a reference to `$stdout`/`$stderr` that was stored before the
749
+ # matcher was used.
750
+ # @note `to_stdout_from_any_process` and `to_stderr_from_any_process` use Tempfiles, and
751
+ # are thus significantly (~30x) slower than `to_stdout` and `to_stderr`.
752
+ def output(expected=nil)
753
+ BuiltIn::Output.new(expected)
754
+ end
755
+ alias_matcher :a_block_outputting, :output
508
756
 
509
757
  # With no args, matches if any error is raised.
510
758
  # With a named error, matches only if that specific error is raised.
511
- # With a named error and messsage specified as a String, matches only if both match.
512
- # With a named error and messsage specified as a Regexp, matches only if both match.
759
+ # With a named error and message specified as a String, matches only if both match.
760
+ # With a named error and message specified as a Regexp, matches only if both match.
513
761
  # Pass an optional block to perform extra verifications on the exception matched
514
762
  #
515
763
  # @example
516
- #
517
764
  # expect { do_something_risky }.to raise_error
518
765
  # expect { do_something_risky }.to raise_error(PoorRiskDecisionError)
519
766
  # expect { do_something_risky }.to raise_error(PoorRiskDecisionError) { |error| expect(error.data).to eq 42 }
767
+ # expect { do_something_risky }.to raise_error { |error| expect(error.data).to eq 42 }
520
768
  # expect { do_something_risky }.to raise_error(PoorRiskDecisionError, "that was too risky")
521
769
  # expect { do_something_risky }.to raise_error(PoorRiskDecisionError, /oo ri/)
770
+ # expect { do_something_risky }.to raise_error("that was too risky")
522
771
  #
523
772
  # expect { do_something_risky }.not_to raise_error
524
- # expect { do_something_risky }.not_to raise_error(PoorRiskDecisionError)
525
- # expect { do_something_risky }.not_to raise_error(PoorRiskDecisionError, "that was too risky")
526
- # expect { do_something_risky }.not_to raise_error(PoorRiskDecisionError, /oo ri/)
527
- def raise_error(error=Exception, message=nil, &block)
773
+ def raise_error(error=BuiltIn::RaiseError::UndefinedValue, message=nil, &block)
528
774
  BuiltIn::RaiseError.new(error, message, &block)
529
775
  end
530
-
531
776
  alias_method :raise_exception, :raise_error
532
777
 
778
+ alias_matcher :a_block_raising, :raise_error do |desc|
779
+ desc.sub("raise", "a block raising")
780
+ end
781
+
782
+ alias_matcher :raising, :raise_error do |desc|
783
+ desc.sub("raise", "raising")
784
+ end
785
+
533
786
  # Matches if the target object responds to all of the names
534
787
  # provided. Names can be Strings or Symbols.
535
788
  #
536
789
  # @example
537
- #
538
- # expect("string").to respond_to(:length)
790
+ # expect("string").to respond_to(:length)
539
791
  #
540
792
  def respond_to(*names)
541
793
  BuiltIn::RespondTo.new(*names)
542
794
  end
795
+ alias_matcher :an_object_responding_to, :respond_to
796
+ alias_matcher :responding_to, :respond_to
543
797
 
544
798
  # Passes if the submitted block returns true. Yields target to the
545
799
  # block.
@@ -551,12 +805,16 @@ module RSpec
551
805
  # If you do find yourself in such a situation, you could always write
552
806
  # a custom matcher, which would likely make your specs more expressive.
553
807
  #
554
- # @example
808
+ # @param description [String] optional description to be used for this matcher.
555
809
  #
810
+ # @example
556
811
  # expect(5).to satisfy { |n| n > 3 }
557
- def satisfy(&block)
558
- BuiltIn::Satisfy.new(&block)
812
+ # expect(5).to satisfy("be greater than 3") { |n| n > 3 }
813
+ def satisfy(description=nil, &block)
814
+ BuiltIn::Satisfy.new(description, &block)
559
815
  end
816
+ alias_matcher :an_object_satisfying, :satisfy
817
+ alias_matcher :satisfying, :satisfy
560
818
 
561
819
  # Matches if the actual value starts with the expected value(s). In the
562
820
  # case of a string, matches against the first `expected.length` characters
@@ -564,13 +822,15 @@ module RSpec
564
822
  # `expected.length` elements of the actual array.
565
823
  #
566
824
  # @example
567
- #
568
825
  # expect("this string").to start_with "this s"
569
826
  # expect([0, 1, 2, 3, 4]).to start_with 0
570
827
  # expect([0, 2, 3, 4, 4]).to start_with 0, 1
571
828
  def start_with(*expected)
572
829
  BuiltIn::StartWith.new(*expected)
573
830
  end
831
+ alias_matcher :a_collection_starting_with, :start_with
832
+ alias_matcher :a_string_starting_with, :start_with
833
+ alias_matcher :starting_with, :start_with
574
834
 
575
835
  # Given no argument, matches if a proc throws any Symbol.
576
836
  #
@@ -580,7 +840,6 @@ module RSpec
580
840
  # specified Symbol with the specified arg.
581
841
  #
582
842
  # @example
583
- #
584
843
  # expect { do_something_risky }.to throw_symbol
585
844
  # expect { do_something_risky }.to throw_symbol(:that_was_risky)
586
845
  # expect { do_something_risky }.to throw_symbol(:that_was_risky, 'culprit')
@@ -592,27 +851,33 @@ module RSpec
592
851
  BuiltIn::ThrowSymbol.new(expected_symbol, expected_arg)
593
852
  end
594
853
 
854
+ alias_matcher :a_block_throwing, :throw_symbol do |desc|
855
+ desc.sub("throw", "a block throwing")
856
+ end
857
+
858
+ alias_matcher :throwing, :throw_symbol do |desc|
859
+ desc.sub("throw", "throwing")
860
+ end
861
+
595
862
  # Passes if the method called in the expect block yields, regardless
596
863
  # of whether or not arguments are yielded.
597
864
  #
598
865
  # @example
599
- #
600
866
  # expect { |b| 5.tap(&b) }.to yield_control
601
867
  # expect { |b| "a".to_sym(&b) }.not_to yield_control
602
868
  #
603
869
  # @note Your expect block must accept a parameter and pass it on to
604
870
  # the method-under-test as a block.
605
- # @note This matcher is not designed for use with methods that yield
606
- # multiple times.
607
871
  def yield_control
608
872
  BuiltIn::YieldControl.new
609
873
  end
874
+ alias_matcher :a_block_yielding_control, :yield_control
875
+ alias_matcher :yielding_control, :yield_control
610
876
 
611
877
  # Passes if the method called in the expect block yields with
612
878
  # no arguments. Fails if it does not yield, or yields with arguments.
613
879
  #
614
880
  # @example
615
- #
616
881
  # expect { |b| User.transaction(&b) }.to yield_with_no_args
617
882
  # expect { |b| 5.tap(&b) }.not_to yield_with_no_args # because it yields with `5`
618
883
  # expect { |b| "a".to_sym(&b) }.not_to yield_with_no_args # because it does not yield
@@ -624,6 +889,8 @@ module RSpec
624
889
  def yield_with_no_args
625
890
  BuiltIn::YieldWithNoArgs.new
626
891
  end
892
+ alias_matcher :a_block_yielding_with_no_args, :yield_with_no_args
893
+ alias_matcher :yielding_with_no_args, :yield_with_no_args
627
894
 
628
895
  # Given no arguments, matches if the method called in the expect
629
896
  # block yields with arguments (regardless of what they are or how
@@ -637,10 +904,9 @@ module RSpec
637
904
  # operator, the matcher will pass.
638
905
  #
639
906
  # @example
640
- #
641
907
  # expect { |b| 5.tap(&b) }.to yield_with_args # because #tap yields an arg
642
908
  # expect { |b| 5.tap(&b) }.to yield_with_args(5) # because 5 == 5
643
- # expect { |b| 5.tap(&b) }.to yield_with_args(Fixnum) # because Fixnum === 5
909
+ # expect { |b| 5.tap(&b) }.to yield_with_args(Integer) # because Integer === 5
644
910
  # expect { |b| File.open("f.txt", &b) }.to yield_with_args(/txt/) # because /txt/ === "f.txt"
645
911
  #
646
912
  # expect { |b| User.transaction(&b) }.not_to yield_with_args # because it yields no args
@@ -653,6 +919,8 @@ module RSpec
653
919
  def yield_with_args(*args)
654
920
  BuiltIn::YieldWithArgs.new(*args)
655
921
  end
922
+ alias_matcher :a_block_yielding_with_args, :yield_with_args
923
+ alias_matcher :yielding_with_args, :yield_with_args
656
924
 
657
925
  # Designed for use with methods that repeatedly yield (such as
658
926
  # iterators). Passes if the method called in the expect block yields
@@ -663,7 +931,6 @@ module RSpec
663
931
  # operator, the matcher will pass.
664
932
  #
665
933
  # @example
666
- #
667
934
  # expect { |b| [1, 2, 3].each(&b) }.to yield_successive_args(1, 2, 3)
668
935
  # expect { |b| { :a => 1, :b => 2 }.each(&b) }.to yield_successive_args([:a, 1], [:b, 2])
669
936
  # expect { |b| [1, 2, 3].each(&b) }.not_to yield_successive_args(1, 2)
@@ -673,25 +940,105 @@ module RSpec
673
940
  def yield_successive_args(*args)
674
941
  BuiltIn::YieldSuccessiveArgs.new(*args)
675
942
  end
943
+ alias_matcher :a_block_yielding_successive_args, :yield_successive_args
944
+ alias_matcher :yielding_successive_args, :yield_successive_args
676
945
 
677
- # Passes if actual contains all of the expected regardless of order.
678
- # This works for collections. Pass in multiple args and it will only
679
- # pass if all args are found in collection.
680
- #
681
- # @note This is also available using the `=~` operator with `should`,
682
- # but `=~` is not supported with `expect`.
683
- #
684
- # @note This matcher only supports positive expectations.
685
- # expect(..).not_to match_array(other_array) is not supported.
686
- #
687
- # @example
688
- #
689
- # expect([1,2,3]).to match_array([1,2,3])
690
- # expect([1,2,3]).to match_array([1,3,2])
691
- def match_array(array)
692
- BuiltIn::MatchArray.new(array)
946
+ # Delegates to {RSpec::Expectations.configuration}.
947
+ # This is here because rspec-core's `expect_with` option
948
+ # looks for a `configuration` method on the mixin
949
+ # (`RSpec::Matchers`) to yield to a block.
950
+ # @return [RSpec::Expectations::Configuration] the configuration object
951
+ def self.configuration
952
+ Expectations.configuration
953
+ end
954
+
955
+ private
956
+
957
+ BE_PREDICATE_REGEX = /^(?:be_(?:an?_)?)(.*)/
958
+ HAS_REGEX = /^(?:have_)(.*)/
959
+ DYNAMIC_MATCHER_REGEX = Regexp.union(BE_PREDICATE_REGEX, HAS_REGEX)
960
+
961
+ def method_missing(method, *args, &block)
962
+ case method.to_s
963
+ when BE_PREDICATE_REGEX
964
+ BuiltIn::BePredicate.new(method, *args, &block)
965
+ when HAS_REGEX
966
+ BuiltIn::Has.new(method, *args, &block)
967
+ else
968
+ super
969
+ end
693
970
  end
971
+ ruby2_keywords :method_missing if respond_to?(:ruby2_keywords, true)
694
972
 
695
- OperatorMatcher.register(Enumerable, '=~', BuiltIn::MatchArray)
973
+ if RUBY_VERSION.to_f >= 1.9
974
+ def respond_to_missing?(method, *)
975
+ method =~ DYNAMIC_MATCHER_REGEX || super
976
+ end
977
+ else # for 1.8.7
978
+ # :nocov:
979
+ def respond_to?(method, *)
980
+ method = method.to_s
981
+ method =~ DYNAMIC_MATCHER_REGEX || super
982
+ end
983
+ public :respond_to?
984
+ # :nocov:
985
+ end
986
+
987
+ # @api private
988
+ def self.is_a_matcher?(obj)
989
+ return true if ::RSpec::Matchers::BuiltIn::BaseMatcher === obj
990
+ begin
991
+ return false if obj.respond_to?(:i_respond_to_everything_so_im_not_really_a_matcher)
992
+ rescue NoMethodError
993
+ # Some objects, like BasicObject, don't implemented standard
994
+ # reflection methods.
995
+ return false
996
+ end
997
+ return false unless obj.respond_to?(:matches?)
998
+
999
+ obj.respond_to?(:failure_message) ||
1000
+ obj.respond_to?(:failure_message_for_should) # support legacy matchers
1001
+ end
1002
+
1003
+ ::RSpec::Support.register_matcher_definition do |obj|
1004
+ is_a_matcher?(obj)
1005
+ end
1006
+
1007
+ # @api private
1008
+ def self.is_a_describable_matcher?(obj)
1009
+ is_a_matcher?(obj) && obj.respond_to?(:description)
1010
+ end
1011
+
1012
+ class << self
1013
+ private
1014
+
1015
+ if RSpec::Support::Ruby.mri? && RUBY_VERSION[0, 3] == '1.9'
1016
+ # Note that `included` doesn't work for this because it is triggered
1017
+ # _after_ `RSpec::Matchers` is an ancestor of the inclusion host, rather
1018
+ # than _before_, like `append_features`. It's important we check this before
1019
+ # in order to find the cases where it was already previously included.
1020
+ # @api private
1021
+ def append_features(mod)
1022
+ return super if mod < self # `mod < self` indicates a re-inclusion.
1023
+
1024
+ subclasses = ObjectSpace.each_object(Class).select { |c| c < mod && c < self }
1025
+ return super unless subclasses.any?
1026
+
1027
+ subclasses.reject! { |s| subclasses.any? { |s2| s < s2 } } # Filter to the root ancestor.
1028
+ subclasses = subclasses.map { |s| "`#{s}`" }.join(", ")
1029
+
1030
+ RSpec.warning "`#{self}` has been included in a superclass (`#{mod}`) " \
1031
+ "after previously being included in subclasses (#{subclasses}), " \
1032
+ "which can trigger infinite recursion from `super` due to an MRI 1.9 bug " \
1033
+ "(https://redmine.ruby-lang.org/issues/3351). To work around this, " \
1034
+ "either upgrade to MRI 2.0+, include a dup of the module (e.g. " \
1035
+ "`include #{self}.dup`), or find a way to include `#{self}` in `#{mod}` " \
1036
+ "before it is included in subclasses (#{subclasses}). See " \
1037
+ "https://github.com/rspec/rspec-expectations/issues/814 for more info"
1038
+
1039
+ super
1040
+ end
1041
+ end
1042
+ end
696
1043
  end
697
1044
  end