rspec-expectations 3.0.0.beta1 → 3.0.0.beta2

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 (122) hide show
  1. data.tar.gz.sig +2 -2
  2. data/.yardopts +1 -0
  3. data/Changelog.md +138 -0
  4. data/README.md +75 -8
  5. data/features/README.md +2 -2
  6. data/features/built_in_matchers/README.md +12 -9
  7. data/features/built_in_matchers/comparisons.feature +2 -2
  8. data/features/built_in_matchers/contain_exactly.feature +46 -0
  9. data/features/built_in_matchers/expect_change.feature +2 -2
  10. data/features/built_in_matchers/include.feature +0 -48
  11. data/features/built_in_matchers/output.feature +70 -0
  12. data/features/composing_matchers.feature +250 -0
  13. data/features/compound_expectations.feature +45 -0
  14. data/features/custom_matchers/access_running_example.feature +1 -1
  15. data/features/custom_matchers/define_matcher.feature +6 -6
  16. data/features/custom_matchers/define_matcher_outside_rspec.feature +4 -8
  17. data/features/test_frameworks/{test_unit.feature → minitest.feature} +11 -11
  18. data/lib/rspec/expectations.rb +31 -42
  19. data/lib/rspec/expectations/diff_presenter.rb +141 -0
  20. data/lib/rspec/expectations/differ.rb +22 -132
  21. data/lib/rspec/expectations/encoded_string.rb +56 -0
  22. data/lib/rspec/expectations/expectation_target.rb +0 -30
  23. data/lib/rspec/expectations/fail_with.rb +2 -2
  24. data/lib/rspec/expectations/handler.rb +128 -31
  25. data/lib/rspec/expectations/minitest_integration.rb +16 -0
  26. data/lib/rspec/expectations/syntax.rb +4 -58
  27. data/lib/rspec/expectations/version.rb +1 -1
  28. data/lib/rspec/matchers.rb +298 -60
  29. data/lib/rspec/matchers/aliased_matcher.rb +35 -0
  30. data/lib/rspec/matchers/built_in.rb +37 -33
  31. data/lib/rspec/matchers/built_in/base_matcher.rb +25 -15
  32. data/lib/rspec/matchers/built_in/be.rb +23 -31
  33. data/lib/rspec/matchers/built_in/be_between.rb +55 -0
  34. data/lib/rspec/matchers/built_in/be_within.rb +15 -11
  35. data/lib/rspec/matchers/built_in/change.rb +198 -81
  36. data/lib/rspec/matchers/built_in/compound.rb +106 -0
  37. data/lib/rspec/matchers/built_in/contain_exactly.rb +245 -0
  38. data/lib/rspec/matchers/built_in/eq.rb +43 -4
  39. data/lib/rspec/matchers/built_in/eql.rb +2 -2
  40. data/lib/rspec/matchers/built_in/equal.rb +35 -18
  41. data/lib/rspec/matchers/built_in/has.rb +16 -15
  42. data/lib/rspec/matchers/built_in/include.rb +45 -23
  43. data/lib/rspec/matchers/built_in/match.rb +6 -3
  44. data/lib/rspec/matchers/built_in/operators.rb +103 -0
  45. data/lib/rspec/matchers/built_in/output.rb +108 -0
  46. data/lib/rspec/matchers/built_in/raise_error.rb +9 -15
  47. data/lib/rspec/matchers/built_in/respond_to.rb +5 -4
  48. data/lib/rspec/matchers/built_in/satisfy.rb +4 -3
  49. data/lib/rspec/matchers/built_in/start_and_end_with.rb +37 -16
  50. data/lib/rspec/matchers/built_in/throw_symbol.rb +6 -5
  51. data/lib/rspec/matchers/built_in/yield.rb +31 -29
  52. data/lib/rspec/matchers/composable.rb +138 -0
  53. data/lib/rspec/matchers/dsl.rb +330 -0
  54. data/lib/rspec/matchers/generated_descriptions.rb +6 -6
  55. data/lib/rspec/matchers/matcher_delegator.rb +33 -0
  56. data/lib/rspec/matchers/pretty.rb +13 -2
  57. data/spec/rspec/expectations/{differ_spec.rb → diff_presenter_spec.rb} +56 -36
  58. data/spec/rspec/expectations/encoded_string_spec.rb +74 -0
  59. data/spec/rspec/expectations/extensions/kernel_spec.rb +11 -11
  60. data/spec/rspec/expectations/fail_with_spec.rb +8 -8
  61. data/spec/rspec/expectations/handler_spec.rb +27 -49
  62. data/spec/rspec/expectations/minitest_integration_spec.rb +27 -0
  63. data/spec/rspec/expectations/syntax_spec.rb +17 -67
  64. data/spec/rspec/expectations_spec.rb +7 -52
  65. data/spec/rspec/matchers/aliased_matcher_spec.rb +48 -0
  66. data/spec/rspec/matchers/aliases_spec.rb +449 -0
  67. data/spec/rspec/matchers/{base_matcher_spec.rb → built_in/base_matcher_spec.rb} +24 -3
  68. data/spec/rspec/matchers/built_in/be_between_spec.rb +159 -0
  69. data/spec/rspec/matchers/{be_instance_of_spec.rb → built_in/be_instance_of_spec.rb} +0 -0
  70. data/spec/rspec/matchers/{be_kind_of_spec.rb → built_in/be_kind_of_spec.rb} +0 -0
  71. data/spec/rspec/matchers/{be_spec.rb → built_in/be_spec.rb} +76 -32
  72. data/spec/rspec/matchers/{be_within_spec.rb → built_in/be_within_spec.rb} +6 -2
  73. data/spec/rspec/matchers/{change_spec.rb → built_in/change_spec.rb} +310 -69
  74. data/spec/rspec/matchers/built_in/compound_spec.rb +292 -0
  75. data/spec/rspec/matchers/built_in/contain_exactly_spec.rb +441 -0
  76. data/spec/rspec/matchers/{cover_spec.rb → built_in/cover_spec.rb} +0 -0
  77. data/spec/rspec/matchers/built_in/eq_spec.rb +156 -0
  78. data/spec/rspec/matchers/{eql_spec.rb → built_in/eql_spec.rb} +2 -2
  79. data/spec/rspec/matchers/built_in/equal_spec.rb +106 -0
  80. data/spec/rspec/matchers/{exist_spec.rb → built_in/exist_spec.rb} +1 -1
  81. data/spec/rspec/matchers/{has_spec.rb → built_in/has_spec.rb} +39 -0
  82. data/spec/rspec/matchers/{include_spec.rb → built_in/include_spec.rb} +118 -109
  83. data/spec/rspec/matchers/{match_spec.rb → built_in/match_spec.rb} +30 -2
  84. data/spec/rspec/matchers/{operator_matcher_spec.rb → built_in/operators_spec.rb} +26 -26
  85. data/spec/rspec/matchers/built_in/output_spec.rb +165 -0
  86. data/spec/rspec/matchers/{raise_error_spec.rb → built_in/raise_error_spec.rb} +81 -11
  87. data/spec/rspec/matchers/{respond_to_spec.rb → built_in/respond_to_spec.rb} +0 -0
  88. data/spec/rspec/matchers/{satisfy_spec.rb → built_in/satisfy_spec.rb} +0 -0
  89. data/spec/rspec/matchers/{start_with_end_with_spec.rb → built_in/start_and_end_with_spec.rb} +82 -15
  90. data/spec/rspec/matchers/{throw_symbol_spec.rb → built_in/throw_symbol_spec.rb} +29 -10
  91. data/spec/rspec/matchers/{yield_spec.rb → built_in/yield_spec.rb} +90 -0
  92. data/spec/rspec/matchers/configuration_spec.rb +7 -39
  93. data/spec/rspec/matchers/description_generation_spec.rb +22 -6
  94. data/spec/rspec/matchers/dsl_spec.rb +838 -0
  95. data/spec/rspec/matchers/legacy_spec.rb +101 -0
  96. data/spec/rspec/matchers_spec.rb +74 -0
  97. data/spec/spec_helper.rb +35 -21
  98. data/spec/support/shared_examples.rb +26 -4
  99. metadata +172 -116
  100. metadata.gz.sig +3 -4
  101. checksums.yaml +0 -15
  102. checksums.yaml.gz.sig +0 -0
  103. data/features/built_in_matchers/match_array.feature +0 -37
  104. data/lib/rspec/expectations/errors.rb +0 -9
  105. data/lib/rspec/expectations/extensions.rb +0 -1
  106. data/lib/rspec/expectations/extensions/object.rb +0 -29
  107. data/lib/rspec/matchers/built_in/match_array.rb +0 -51
  108. data/lib/rspec/matchers/compatibility.rb +0 -14
  109. data/lib/rspec/matchers/matcher.rb +0 -301
  110. data/lib/rspec/matchers/method_missing.rb +0 -12
  111. data/lib/rspec/matchers/operator_matcher.rb +0 -99
  112. data/lib/rspec/matchers/test_unit_integration.rb +0 -11
  113. data/spec/rspec/matchers/eq_spec.rb +0 -60
  114. data/spec/rspec/matchers/equal_spec.rb +0 -78
  115. data/spec/rspec/matchers/include_matcher_integration_spec.rb +0 -30
  116. data/spec/rspec/matchers/match_array_spec.rb +0 -194
  117. data/spec/rspec/matchers/matcher_spec.rb +0 -706
  118. data/spec/rspec/matchers/matchers_spec.rb +0 -36
  119. data/spec/rspec/matchers/method_missing_spec.rb +0 -28
  120. data/spec/support/classes.rb +0 -56
  121. data/spec/support/in_sub_process.rb +0 -37
  122. data/spec/support/ruby_version.rb +0 -10
@@ -1,26 +1,22 @@
1
1
  require 'rspec/matchers/pretty'
2
-
2
+ require 'rspec/matchers/composable'
3
3
  require 'rspec/matchers/built_in'
4
- require 'rspec/matchers/matcher'
5
- require 'rspec/matchers/operator_matcher'
6
-
7
4
  require 'rspec/matchers/generated_descriptions'
8
- require 'rspec/matchers/method_missing'
9
- require 'rspec/matchers/compatibility'
10
5
  require 'rspec/matchers/dsl'
11
- require 'rspec/matchers/test_unit_integration'
6
+ require 'rspec/matchers/matcher_delegator'
7
+ require 'rspec/matchers/aliased_matcher'
12
8
 
13
9
  module RSpec
14
10
  # RSpec::Matchers provides a number of useful matchers we use to define
15
11
  # expectations. A matcher is any object that responds to the following:
16
12
  #
17
13
  # matches?(actual)
18
- # failure_message_for_should
14
+ # failure_message
19
15
  #
20
16
  # These methods are also part of the matcher protocol, but are optional:
21
17
  #
22
18
  # does_not_match?(actual)
23
- # failure_message_for_should_not
19
+ # failure_message_when_negated
24
20
  # description
25
21
  #
26
22
  # ## Predicates
@@ -59,6 +55,12 @@ module RSpec
59
55
  # You can use this feature to invoke any predicate that begins with "has_", whether it is
60
56
  # part of the Ruby libraries (like `Hash#has_key?`) or a method you wrote on your own class.
61
57
  #
58
+ # Note that RSpec does not provide composable aliases for these dynamic predicate
59
+ # matchers. You can easily define your own aliases, though:
60
+ #
61
+ # RSpec::Matchers.alias_matcher :a_user_who_is_an_admin, :be_an_admin
62
+ # expect(user_list).to include(a_user_who_is_an_admin)
63
+ #
62
64
  # ## Custom Matchers
63
65
  #
64
66
  # When you find that none of the stock matchers provide a natural feeling
@@ -98,11 +100,11 @@ module RSpec
98
100
  # player.in_zone?(zone)
99
101
  # end
100
102
  #
101
- # failure_message_for_should do |player|
103
+ # failure_message do |player|
102
104
  # # generate and return the appropriate string.
103
105
  # end
104
106
  #
105
- # failure_message_for_should_not do |player|
107
+ # failure_message_when_negated do |player|
106
108
  # # generate and return the appropriate string.
107
109
  # end
108
110
  #
@@ -113,8 +115,8 @@ module RSpec
113
115
  #
114
116
  # Each of the message-generation methods has access to the block arguments
115
117
  # passed to the <tt>create</tt> method (in this case, <tt>zone</tt>). The
116
- # failure message methods (<tt>failure_message_for_should</tt> and
117
- # <tt>failure_message_for_should_not</tt>) are passed the actual value (the
118
+ # failure message methods (<tt>failure_message</tt> and
119
+ # <tt>failure_message_when_negated</tt>) are passed the actual value (the
118
120
  # receiver of <tt>expect(..)</tt> or <tt>expect(..).not_to</tt>).
119
121
  #
120
122
  # ### Custom Matcher from scratch
@@ -131,11 +133,11 @@ module RSpec
131
133
  # @target.current_zone.eql?(Zone.new(@expected))
132
134
  # end
133
135
  #
134
- # def failure_message_for_should
136
+ # def failure_message
135
137
  # "expected #{@target.inspect} to be in Zone #{@expected}"
136
138
  # end
137
139
  #
138
- # def failure_message_for_should_not
140
+ # def failure_message_when_negated
139
141
  # "expected #{@target.inspect} not to be in Zone #{@expected}"
140
142
  # end
141
143
  # end
@@ -171,32 +173,90 @@ module RSpec
171
173
  # RSpec::configure do |config|
172
174
  # config.include(CustomGameMatchers)
173
175
  # end
176
+ #
177
+ # ### Making custom matchers composable
178
+ #
179
+ # RSpec's built-in matchers are designed to be composed, in expressions like:
180
+ #
181
+ # expect(["barn", 2.45]).to contain_exactly(
182
+ # a_value_within(0.1).of(2.5),
183
+ # a_string_starting_with("bar")
184
+ # )
185
+ #
186
+ # Custom matchers can easily participate in composed matcher expressions like these.
187
+ # Include {RSpec::Matchers::Composable} in your custom matcher to make it support
188
+ # being composed (matchers defined using the DSL have this included automatically).
189
+ # Within your matcher's `matches?` method (or the `match` block, if using the DSL),
190
+ # use `values_match?(expected, actual)` rather than `expected == actual`.
191
+ # Under the covers, `values_match?` is able to match arbitrary
192
+ # nested data structures containing a mix of both matchers and non-matcher objects.
193
+ # It uses `===` and `==` to perform the matching, considering the values to
194
+ # match if either returns `true`. The `Composable` mixin also provides some helper
195
+ # methods for surfacing the matcher descriptions within your matcher's description
196
+ # or failure messages.
197
+ #
198
+ # RSpec's built-in matchers each have a number of aliases that rephrase the matcher
199
+ # from a verb phrase (such as `be_within`) to a noun phrase (such as `a_value_within`),
200
+ # which reads better when the matcher is passed as an argument in a composed matcher
201
+ # expressions, and also uses the noun-phrase wording in the matcher's `description`,
202
+ # for readable failure messages. You can alias your custom matchers in similar fashion
203
+ # using {RSpec::Matchers.alias_matcher}.
174
204
  module Matchers
175
- # @api private
176
- def self.is_a_matcher?(obj)
177
- return true if ::RSpec::Matchers::BuiltIn::BaseMatcher === obj
178
- return false if obj.respond_to?(:i_respond_to_everything_so_im_not_really_a_matcher)
179
- return false unless obj.respond_to?(:matches?)
180
-
181
- obj.respond_to?(:failure_message_for_should) || obj.respond_to?(:failure_message)
205
+ # Defines a matcher alias. The returned matcher's `description` will be overriden
206
+ # to reflect the phrasing of the new name, which will be used in failure messages
207
+ # when passed as an argument to another matcher in a composed matcher expression.
208
+ #
209
+ # @param new_name [Symbol] the new name for the matcher
210
+ # @param old_name [Symbol] the original name for the matcher
211
+ # @yield [String] optional block that, when given is used to define the overriden
212
+ # description. The yielded arg is the original description. If no block is
213
+ # provided, a default description override is used based on the old and
214
+ # new names.
215
+ #
216
+ # @example
217
+ #
218
+ # RSpec::Matchers.alias_matcher :a_list_that_sums_to, :sum_to
219
+ # sum_to(3).description # => "sum to 3"
220
+ # a_list_that_sums_to(3).description # => "a list that sums to 3"
221
+ #
222
+ # @example
223
+ #
224
+ # RSpec::Matchers.alias_matcher :a_list_sorted_by, :be_sorted_by do |description|
225
+ # description.sub("be sorted by", "a list sorted by")
226
+ # end
227
+ #
228
+ # be_sorted_by(:age).description # => "be sorted by age"
229
+ # a_list_sorted_by(:age).description # => "a list sorted by age"
230
+ def self.alias_matcher(new_name, old_name, &description_override)
231
+ description_override ||= lambda do |old_desc|
232
+ old_desc.gsub(Pretty.split_words(old_name), Pretty.split_words(new_name))
233
+ end
234
+
235
+ define_method(new_name) do |*args, &block|
236
+ matcher = __send__(old_name, *args, &block)
237
+ AliasedMatcher.new(matcher, description_override)
238
+ end
182
239
  end
183
240
 
184
241
  # Passes if actual is truthy (anything but false or nil)
185
242
  def be_truthy
186
243
  BuiltIn::BeTruthy.new
187
244
  end
245
+ alias_matcher :a_truthy_value, :be_truthy
188
246
 
189
- # Passes if actual is falsy (false or nil)
247
+ # Passes if actual is falsey (false or nil)
190
248
  def be_falsey
191
249
  BuiltIn::BeFalsey.new
192
250
  end
193
-
194
- alias_method :be_falsy, :be_falsey
251
+ alias_matcher :be_falsy, :be_falsey
252
+ alias_matcher :a_falsey_value, :be_falsey
253
+ alias_matcher :a_falsy_value, :be_falsey
195
254
 
196
255
  # Passes if actual is nil
197
256
  def be_nil
198
257
  BuiltIn::BeNil.new
199
258
  end
259
+ alias_matcher :a_nil_value, :be_nil
200
260
 
201
261
  # @example
202
262
  # expect(actual).to be_truthy
@@ -222,12 +282,12 @@ module RSpec
222
282
  args.empty? ?
223
283
  Matchers::BuiltIn::Be.new : equal(*args)
224
284
  end
285
+ alias_matcher :a_value, :be
225
286
 
226
287
  # passes if target.kind_of?(klass)
227
288
  def be_a(klass)
228
289
  be_a_kind_of(klass)
229
290
  end
230
-
231
291
  alias_method :be_an, :be_a
232
292
 
233
293
  # Passes if actual.instance_of?(expected)
@@ -240,8 +300,8 @@ module RSpec
240
300
  def be_an_instance_of(expected)
241
301
  BuiltIn::BeAnInstanceOf.new(expected)
242
302
  end
243
-
244
- alias_method :be_instance_of, :be_an_instance_of
303
+ alias_method :be_instance_of, :be_an_instance_of
304
+ alias_matcher :an_instance_of, :be_an_instance_of
245
305
 
246
306
  # Passes if actual.kind_of?(expected)
247
307
  #
@@ -253,8 +313,25 @@ module RSpec
253
313
  def be_a_kind_of(expected)
254
314
  BuiltIn::BeAKindOf.new(expected)
255
315
  end
316
+ alias_method :be_kind_of, :be_a_kind_of
317
+ alias_matcher :a_kind_of, :be_a_kind_of
256
318
 
257
- alias_method :be_kind_of, :be_a_kind_of
319
+ # Passes if actual.between?(min, max). Works with any Comparable object,
320
+ # including String, Symbol, Time, or Numeric (Fixnum, Bignum, Integer,
321
+ # Float, Complex, and Rational).
322
+ #
323
+ # By default, `be_between` is inclusive (i.e. passes when given either the max or min value),
324
+ # but you can make it `exclusive` by chaining that off the matcher.
325
+ #
326
+ # @example
327
+ #
328
+ # expect(5).to be_between(1, 10)
329
+ # expect(11).not_to be_between(1, 10)
330
+ # expect(10).not_to be_between(1, 10).exclusive
331
+ def be_between(min, max)
332
+ BuiltIn::BeBetween.new(min, max)
333
+ end
334
+ alias_matcher :a_value_between, :be_between
258
335
 
259
336
  # Passes if actual == expected +/- delta
260
337
  #
@@ -265,6 +342,8 @@ module RSpec
265
342
  def be_within(delta)
266
343
  BuiltIn::BeWithin.new(delta)
267
344
  end
345
+ alias_matcher :a_value_within, :be_within
346
+ alias_matcher :within, :be_within
268
347
 
269
348
  # Applied to a proc, specifies that its execution will cause some value to
270
349
  # change.
@@ -275,9 +354,18 @@ module RSpec
275
354
  # You can either pass <tt>receiver</tt> and <tt>message</tt>, or a block,
276
355
  # but not both.
277
356
  #
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.
357
+ # When passing a block, it must use the `{ ... }` format, not
358
+ # do/end, as `{ ... }` binds to the `change` method, whereas do/end
359
+ # would errantly bind to the `expect(..).to` or `expect(...).not_to` method.
360
+ #
361
+ # You can chain any of the following off of the end to specify details
362
+ # about the change:
363
+ #
364
+ # * `by`
365
+ # * `by_at_least`
366
+ # * `by_at_most`
367
+ # * `from`
368
+ # * `to`
281
369
  #
282
370
  # @example
283
371
  #
@@ -305,7 +393,7 @@ module RSpec
305
393
  # string = "string"
306
394
  # expect {
307
395
  # string
308
- # }.not_to change { string }
396
+ # }.not_to change { string }.from("string")
309
397
  #
310
398
  # expect {
311
399
  # person.happy_birthday
@@ -326,15 +414,40 @@ module RSpec
326
414
  #
327
415
  # == Notes
328
416
  #
329
- # Evaluates <tt>receiver.message</tt> or <tt>block</tt> before and after it
330
- # evaluates the block passed to <tt>expect</tt>.
417
+ # Evaluates `receiver.message` or `block` before and after it
418
+ # evaluates the block passed to `expect`.
331
419
  #
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>.
420
+ # `expect( ... ).not_to change` supports the form that specifies `from`
421
+ # (which specifies what you expect the starting, unchanged value to be)
422
+ # but does not support forms with subsequent calls to `by`, `by_at_least`,
423
+ # `by_at_most` or `to`.
335
424
  def change(receiver=nil, message=nil, &block)
336
425
  BuiltIn::Change.new(receiver, message, &block)
337
426
  end
427
+ alias_matcher :a_block_changing, :change
428
+ alias_matcher :changing, :change
429
+
430
+ # Passes if actual contains all of the expected regardless of order.
431
+ # This works for collections. Pass in multiple args and it will only
432
+ # pass if all args are found in collection.
433
+ #
434
+ # @note This is also available using the `=~` operator with `should`,
435
+ # but `=~` is not supported with `expect`.
436
+ #
437
+ # @note This matcher only supports positive expectations.
438
+ # `expect(...).not_to contain_exactly(other_array)` is not supported.
439
+ #
440
+ # @example
441
+ #
442
+ # expect([1, 2, 3]).to contain_exactly(1, 2, 3)
443
+ # expect([1, 2, 3]).to contain_exactly(1, 3, 2)
444
+ #
445
+ # @see #match_array
446
+ def contain_exactly(*items)
447
+ BuiltIn::ContainExactly.new(items)
448
+ end
449
+ alias_matcher :a_collection_containing_exactly, :contain_exactly
450
+ alias_matcher :containing_exactly, :contain_exactly
338
451
 
339
452
  # Passes if actual covers expected. This works for
340
453
  # Ranges. You can also pass in multiple args
@@ -350,7 +463,9 @@ module RSpec
350
463
  # ### Warning:: Ruby >= 1.9 only
351
464
  def cover(*values)
352
465
  BuiltIn::Cover.new(*values)
353
- end if (1..2).respond_to?(:cover?)
466
+ end
467
+ alias_matcher :a_range_covering, :cover
468
+ alias_matcher :covering, :cover
354
469
 
355
470
  # Matches if the actual value ends with the expected value(s). In the case
356
471
  # of a string, matches against the last `expected.length` characters of the
@@ -365,6 +480,9 @@ module RSpec
365
480
  def end_with(*expected)
366
481
  BuiltIn::EndWith.new(*expected)
367
482
  end
483
+ alias_matcher :a_collection_ending_with, :end_with
484
+ alias_matcher :a_string_ending_with, :end_with
485
+ alias_matcher :ending_with, :end_with
368
486
 
369
487
  # Passes if <tt>actual == expected</tt>.
370
488
  #
@@ -378,8 +496,10 @@ module RSpec
378
496
  def eq(expected)
379
497
  BuiltIn::Eq.new(expected)
380
498
  end
499
+ alias_matcher :an_object_eq_to, :eq
500
+ alias_matcher :eq_to, :eq
381
501
 
382
- # Passes if +actual.eql?(expected)+
502
+ # Passes if `actual.eql?(expected)`
383
503
  #
384
504
  # See http://www.ruby-doc.org/core/classes/Object.html#M001057 for more
385
505
  # information about equality in Ruby.
@@ -391,6 +511,8 @@ module RSpec
391
511
  def eql(expected)
392
512
  BuiltIn::Eql.new(expected)
393
513
  end
514
+ alias_matcher :an_object_eql_to, :eql
515
+ alias_matcher :eql_to, :eql
394
516
 
395
517
  # Passes if <tt>actual.equal?(expected)</tt> (object identity).
396
518
  #
@@ -404,6 +526,8 @@ module RSpec
404
526
  def equal(expected)
405
527
  BuiltIn::Equal.new(expected)
406
528
  end
529
+ alias_matcher :an_object_equal_to, :equal
530
+ alias_matcher :equal_to, :equal
407
531
 
408
532
  # Passes if `actual.exist?` or `actual.exists?`
409
533
  #
@@ -412,6 +536,8 @@ module RSpec
412
536
  def exist(*args)
413
537
  BuiltIn::Exist.new(*args)
414
538
  end
539
+ alias_matcher :an_object_existing, :exist
540
+ alias_matcher :existing, :exist
415
541
 
416
542
  # Passes if actual includes expected. This works for
417
543
  # collections and Strings. You can also pass in multiple args
@@ -428,14 +554,40 @@ module RSpec
428
554
  def include(*expected)
429
555
  BuiltIn::Include.new(*expected)
430
556
  end
557
+ alias_matcher :a_collection_including, :include
558
+ alias_matcher :a_string_including, :include
559
+ alias_matcher :a_hash_including, :include
560
+ alias_matcher :including, :include
431
561
 
432
- # Given a Regexp or String, passes if actual.match(pattern)
562
+ # Given a `Regexp` or `String`, passes if `actual.match(pattern)`
563
+ # Given an arbitrary nested data structure (e.g. arrays and hashes),
564
+ # matches if `expected === actual` || `actual == expected` for each
565
+ # pair of elements.
433
566
  #
434
567
  # @example
435
568
  #
436
569
  # expect(email).to match(/^([^\s]+)((?:[-a-z0-9]+\.)+[a-z]{2,})$/i)
437
570
  # expect(email).to match("@example.com")
438
571
  #
572
+ # @example
573
+ #
574
+ # hash = {
575
+ # :a => {
576
+ # :b => ["foo", 5],
577
+ # :c => { :d => 2.05 }
578
+ # }
579
+ # }
580
+ #
581
+ # expect(hash).to match(
582
+ # :a => {
583
+ # :b => a_collection_containing_exactly(
584
+ # a_string_starting_with("f"),
585
+ # an_instance_of(Fixnum)
586
+ # ),
587
+ # :c => { :d => (a_value < 3) }
588
+ # }
589
+ # )
590
+ #
439
591
  # @note The `match_regex` alias is deprecated and is not recommended for use.
440
592
  # It was added in 2.12.1 to facilitate its use from within custom
441
593
  # matchers (due to how the custom matcher DSL was evaluated in 2.x,
@@ -443,7 +595,52 @@ module RSpec
443
595
  def match(expected)
444
596
  BuiltIn::Match.new(expected)
445
597
  end
446
- alias_method :match_regex, :match
598
+ alias_matcher :match_regex, :match
599
+ alias_matcher :an_object_matching, :match
600
+ alias_matcher :a_string_matching, :match
601
+ alias_matcher :matching, :match
602
+
603
+ # An alternate form of `contain_exactly` that accepts
604
+ # the expected contents as a single array arg rather
605
+ # that splatted out as individual items.
606
+ #
607
+ # @example
608
+ #
609
+ # expect(results).to contain_exactly(1, 2)
610
+ # # is identical to:
611
+ # expect(results).to match_array([1, 2])
612
+ #
613
+ # @see #contain_exactly
614
+ def match_array(items)
615
+ contain_exactly(*items)
616
+ end
617
+
618
+ # With no arg, passes if the block outputs `to_stdout` or `to_stderr`.
619
+ # With a string, passes if the blocks outputs that specific string `to_stdout` or `to_stderr`.
620
+ # With a regexp or matcher, passes if the blocks outputs a string `to_stdout` or `to_stderr` that matches.
621
+ #
622
+ # @example
623
+ #
624
+ # expect { print 'foo' }.to output.to_stdout
625
+ # expect { print 'foo' }.to output('foo').to_stdout
626
+ # expect { print 'foo' }.to output(/foo/).to_stdout
627
+ #
628
+ # expect { do_something }.to_not output.to_stdout
629
+ #
630
+ # expect { warn('foo') }.to output.to_stderr
631
+ # expect { warn('foo') }.to output('foo').to_stderr
632
+ # expect { warn('foo') }.to output(/foo/).to_stderr
633
+ #
634
+ # expect { do_something }.to_not output.to_stderr
635
+ #
636
+ # @note This matcher works by temporarily replacing `$stdout` or `$stderr`,
637
+ # so it's not able to intercept stream output that explicitly uses `STDOUT`/`STDERR`
638
+ # or that uses a reference to `$stdout`/`$stderr` that was stored before the
639
+ # matcher is used.
640
+ def output(expected=nil)
641
+ BuiltIn::Output.new(expected)
642
+ end
643
+ alias_matcher :a_block_outputting, :output
447
644
 
448
645
  # With no args, matches if any error is raised.
449
646
  # With a named error, matches only if that specific error is raised.
@@ -463,8 +660,15 @@ module RSpec
463
660
  def raise_error(error=Exception, message=nil, &block)
464
661
  BuiltIn::RaiseError.new(error, message, &block)
465
662
  end
663
+ alias_method :raise_exception, :raise_error
466
664
 
467
- alias_method :raise_exception, :raise_error
665
+ alias_matcher :a_block_raising, :raise_error do |desc|
666
+ desc.sub("raise", "a block raising")
667
+ end
668
+
669
+ alias_matcher :raising, :raise_error do |desc|
670
+ desc.sub("raise", "raising")
671
+ end
468
672
 
469
673
  # Matches if the target object responds to all of the names
470
674
  # provided. Names can be Strings or Symbols.
@@ -476,6 +680,8 @@ module RSpec
476
680
  def respond_to(*names)
477
681
  BuiltIn::RespondTo.new(*names)
478
682
  end
683
+ alias_matcher :an_object_responding_to, :respond_to
684
+ alias_matcher :responding_to, :respond_to
479
685
 
480
686
  # Passes if the submitted block returns true. Yields target to the
481
687
  # block.
@@ -493,6 +699,8 @@ module RSpec
493
699
  def satisfy(&block)
494
700
  BuiltIn::Satisfy.new(&block)
495
701
  end
702
+ alias_matcher :an_object_satisfying, :satisfy
703
+ alias_matcher :satisfying, :satisfy
496
704
 
497
705
  # Matches if the actual value starts with the expected value(s). In the
498
706
  # case of a string, matches against the first `expected.length` characters
@@ -507,6 +715,9 @@ module RSpec
507
715
  def start_with(*expected)
508
716
  BuiltIn::StartWith.new(*expected)
509
717
  end
718
+ alias_matcher :a_collection_starting_with, :start_with
719
+ alias_matcher :a_string_starting_with, :start_with
720
+ alias_matcher :starting_with, :start_with
510
721
 
511
722
  # Given no argument, matches if a proc throws any Symbol.
512
723
  #
@@ -528,6 +739,14 @@ module RSpec
528
739
  BuiltIn::ThrowSymbol.new(expected_symbol, expected_arg)
529
740
  end
530
741
 
742
+ alias_matcher :a_block_throwing, :throw_symbol do |desc|
743
+ desc.sub("throw", "a block throwing")
744
+ end
745
+
746
+ alias_matcher :throwing, :throw_symbol do |desc|
747
+ desc.sub("throw", "throwing")
748
+ end
749
+
531
750
  # Passes if the method called in the expect block yields, regardless
532
751
  # of whether or not arguments are yielded.
533
752
  #
@@ -543,6 +762,8 @@ module RSpec
543
762
  def yield_control
544
763
  BuiltIn::YieldControl.new
545
764
  end
765
+ alias_matcher :a_block_yielding_control, :yield_control
766
+ alias_matcher :yielding_control, :yield_control
546
767
 
547
768
  # Passes if the method called in the expect block yields with
548
769
  # no arguments. Fails if it does not yield, or yields with arguments.
@@ -560,6 +781,8 @@ module RSpec
560
781
  def yield_with_no_args
561
782
  BuiltIn::YieldWithNoArgs.new
562
783
  end
784
+ alias_matcher :a_block_yielding_with_no_args, :yield_with_no_args
785
+ alias_matcher :yielding_with_no_args, :yield_with_no_args
563
786
 
564
787
  # Given no arguments, matches if the method called in the expect
565
788
  # block yields with arguments (regardless of what they are or how
@@ -589,6 +812,8 @@ module RSpec
589
812
  def yield_with_args(*args)
590
813
  BuiltIn::YieldWithArgs.new(*args)
591
814
  end
815
+ alias_matcher :a_block_yielding_with_args, :yield_with_args
816
+ alias_matcher :yielding_with_args, :yield_with_args
592
817
 
593
818
  # Designed for use with methods that repeatedly yield (such as
594
819
  # iterators). Passes if the method called in the expect block yields
@@ -609,25 +834,38 @@ module RSpec
609
834
  def yield_successive_args(*args)
610
835
  BuiltIn::YieldSuccessiveArgs.new(*args)
611
836
  end
837
+ alias_matcher :a_block_yielding_successive_args, :yield_successive_args
838
+ alias_matcher :yielding_successive_args, :yield_successive_args
839
+
840
+ private
841
+
842
+ BE_PREDICATE_REGEX = /^(be_(?:an?_)?)(.*)/
843
+ HAS_REGEX = /^(?:have_)(.*)/
844
+
845
+ def method_missing(method, *args, &block)
846
+ case method.to_s
847
+ when BE_PREDICATE_REGEX
848
+ BuiltIn::BePredicate.new(method, *args, &block)
849
+ when HAS_REGEX
850
+ BuiltIn::Has.new(method, *args, &block)
851
+ else
852
+ super
853
+ end
854
+ end
612
855
 
613
- # Passes if actual contains all of the expected regardless of order.
614
- # This works for collections. Pass in multiple args and it will only
615
- # pass if all args are found in collection.
616
- #
617
- # @note This is also available using the `=~` operator with `should`,
618
- # but `=~` is not supported with `expect`.
619
- #
620
- # @note This matcher only supports positive expectations.
621
- # expect(..).not_to match_array(other_array) is not supported.
622
- #
623
- # @example
624
- #
625
- # expect([1,2,3]).to match_array([1,2,3])
626
- # expect([1,2,3]).to match_array([1,3,2])
627
- def match_array(array)
628
- BuiltIn::MatchArray.new(array)
856
+ # @api private
857
+ def self.is_a_matcher?(obj)
858
+ return true if ::RSpec::Matchers::BuiltIn::BaseMatcher === obj
859
+ return false if obj.respond_to?(:i_respond_to_everything_so_im_not_really_a_matcher)
860
+ return false unless obj.respond_to?(:matches?)
861
+
862
+ obj.respond_to?(:failure_message) ||
863
+ obj.respond_to?(:failure_message_for_should) # support legacy matchers
629
864
  end
630
865
 
631
- OperatorMatcher.register(Enumerable, '=~', BuiltIn::MatchArray)
866
+ # @api private
867
+ def self.is_a_describable_matcher?(obj)
868
+ is_a_matcher?(obj) && obj.respond_to?(:description)
869
+ end
632
870
  end
633
871
  end