rspec-expectations 3.8.1 → 3.12.3

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 (39) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data/Changelog.md +203 -4
  4. data/README.md +35 -20
  5. data/lib/rspec/expectations/configuration.rb +15 -0
  6. data/lib/rspec/expectations/expectation_target.rb +42 -6
  7. data/lib/rspec/expectations/failure_aggregator.rb +41 -6
  8. data/lib/rspec/expectations/handler.rb +20 -8
  9. data/lib/rspec/expectations/version.rb +1 -1
  10. data/lib/rspec/matchers/aliased_matcher.rb +3 -3
  11. data/lib/rspec/matchers/built_in/all.rb +1 -0
  12. data/lib/rspec/matchers/built_in/base_matcher.rb +5 -0
  13. data/lib/rspec/matchers/built_in/be.rb +10 -107
  14. data/lib/rspec/matchers/built_in/be_instance_of.rb +5 -1
  15. data/lib/rspec/matchers/built_in/be_kind_of.rb +5 -1
  16. data/lib/rspec/matchers/built_in/be_within.rb +2 -2
  17. data/lib/rspec/matchers/built_in/change.rb +26 -2
  18. data/lib/rspec/matchers/built_in/compound.rb +20 -1
  19. data/lib/rspec/matchers/built_in/contain_exactly.rb +10 -2
  20. data/lib/rspec/matchers/built_in/count_expectation.rb +169 -0
  21. data/lib/rspec/matchers/built_in/exist.rb +1 -1
  22. data/lib/rspec/matchers/built_in/has.rb +88 -24
  23. data/lib/rspec/matchers/built_in/have_attributes.rb +1 -1
  24. data/lib/rspec/matchers/built_in/include.rb +82 -18
  25. data/lib/rspec/matchers/built_in/output.rb +7 -0
  26. data/lib/rspec/matchers/built_in/raise_error.rb +63 -22
  27. data/lib/rspec/matchers/built_in/respond_to.rb +53 -18
  28. data/lib/rspec/matchers/built_in/throw_symbol.rb +10 -4
  29. data/lib/rspec/matchers/built_in/yield.rb +26 -83
  30. data/lib/rspec/matchers/built_in.rb +2 -1
  31. data/lib/rspec/matchers/composable.rb +1 -1
  32. data/lib/rspec/matchers/dsl.rb +29 -11
  33. data/lib/rspec/matchers/english_phrasing.rb +1 -1
  34. data/lib/rspec/matchers/expecteds_for_multiple_diffs.rb +16 -7
  35. data/lib/rspec/matchers/matcher_protocol.rb +6 -0
  36. data/lib/rspec/matchers.rb +78 -68
  37. data.tar.gz.sig +0 -0
  38. metadata +29 -24
  39. metadata.gz.sig +0 -0
@@ -93,7 +93,7 @@ module RSpec
93
93
  end
94
94
 
95
95
  def respond_to_matcher
96
- @respond_to_matcher ||= RespondTo.new(*expected.keys).with(0).arguments
96
+ @respond_to_matcher ||= RespondTo.new(*expected.keys).with(0).arguments.tap { |m| m.ignoring_method_signature_failure! }
97
97
  end
98
98
 
99
99
  def respond_to_failure_message_or
@@ -1,13 +1,17 @@
1
+ require 'rspec/matchers/built_in/count_expectation'
2
+
1
3
  module RSpec
2
4
  module Matchers
3
5
  module BuiltIn
4
6
  # @api private
5
7
  # Provides the implementation for `include`.
6
8
  # Not intended to be instantiated directly.
7
- class Include < BaseMatcher
9
+ class Include < BaseMatcher # rubocop:disable Metrics/ClassLength
10
+ include CountExpectation
8
11
  # @private
9
12
  attr_reader :expecteds
10
13
 
14
+ # @api private
11
15
  def initialize(*expecteds)
12
16
  @expecteds = expecteds
13
17
  end
@@ -15,21 +19,29 @@ module RSpec
15
19
  # @api private
16
20
  # @return [Boolean]
17
21
  def matches?(actual)
18
- actual = actual.to_hash if convert_to_hash?(actual)
19
- perform_match(actual) { |v| v }
22
+ check_actual?(actual) &&
23
+ if check_expected_count?
24
+ expected_count_matches?(count_inclusions)
25
+ else
26
+ perform_match { |v| v }
27
+ end
20
28
  end
21
29
 
22
30
  # @api private
23
31
  # @return [Boolean]
24
32
  def does_not_match?(actual)
25
- actual = actual.to_hash if convert_to_hash?(actual)
26
- perform_match(actual) { |v| !v }
33
+ check_actual?(actual) &&
34
+ if check_expected_count?
35
+ !expected_count_matches?(count_inclusions)
36
+ else
37
+ perform_match { |v| !v }
38
+ end
27
39
  end
28
40
 
29
41
  # @api private
30
42
  # @return [String]
31
43
  def description
32
- improve_hash_formatting("include#{readable_list_of(expecteds)}")
44
+ improve_hash_formatting("include#{readable_list_of(expecteds)}#{count_expectation_description}")
33
45
  end
34
46
 
35
47
  # @api private
@@ -62,12 +74,33 @@ module RSpec
62
74
 
63
75
  private
64
76
 
65
- def format_failure_message(preposition)
66
- if actual.respond_to?(:include?)
67
- improve_hash_formatting("expected #{description_of @actual} #{preposition} include#{readable_list_of @divergent_items}")
68
- else
69
- improve_hash_formatting(yield) + ", but it does not respond to `include?`"
77
+ def check_actual?(actual)
78
+ actual = actual.to_hash if convert_to_hash?(actual)
79
+ @actual = actual
80
+ @actual.respond_to?(:include?)
81
+ end
82
+
83
+ def check_expected_count?
84
+ case
85
+ when !has_expected_count?
86
+ return false
87
+ when expecteds.size != 1
88
+ raise NotImplementedError, 'Count constraint supported only when testing for a single value being included'
89
+ when actual.is_a?(Hash)
90
+ raise NotImplementedError, 'Count constraint on hash keys not implemented'
70
91
  end
92
+ true
93
+ end
94
+
95
+ def format_failure_message(preposition)
96
+ msg = if actual.respond_to?(:include?)
97
+ "expected #{description_of @actual} #{preposition}" \
98
+ " include#{readable_list_of @divergent_items}" \
99
+ "#{count_failure_reason('it is included') if has_expected_count?}"
100
+ else
101
+ "#{yield}, but it does not respond to `include?`"
102
+ end
103
+ improve_hash_formatting(msg)
71
104
  end
72
105
 
73
106
  def readable_list_of(items)
@@ -79,10 +112,9 @@ module RSpec
79
112
  end
80
113
  end
81
114
 
82
- def perform_match(actual, &block)
83
- @actual = actual
115
+ def perform_match(&block)
84
116
  @divergent_items = excluded_from_actual(&block)
85
- actual.respond_to?(:include?) && @divergent_items.empty?
117
+ @divergent_items.empty?
86
118
  end
87
119
 
88
120
  def excluded_from_actual
@@ -107,7 +139,10 @@ module RSpec
107
139
  end
108
140
 
109
141
  def actual_hash_includes?(expected_key, expected_value)
110
- actual_value = actual.fetch(expected_key) { return false }
142
+ actual_value =
143
+ actual.fetch(expected_key) do
144
+ actual.find(Proc.new { return false }) { |actual_key, _| values_match?(expected_key, actual_key) }[1]
145
+ end
111
146
  values_match?(expected_value, actual_value)
112
147
  end
113
148
 
@@ -118,8 +153,15 @@ module RSpec
118
153
  def actual_hash_has_key?(expected_key)
119
154
  # We check `key?` first for perf:
120
155
  # `key?` is O(1), but `any?` is O(N).
121
- actual.key?(expected_key) ||
122
- actual.keys.any? { |key| values_match?(expected_key, key) }
156
+
157
+ has_exact_key =
158
+ begin
159
+ actual.key?(expected_key)
160
+ rescue
161
+ false
162
+ end
163
+
164
+ has_exact_key || actual.keys.any? { |key| values_match?(expected_key, key) }
123
165
  end
124
166
 
125
167
  def actual_collection_includes?(expected_item)
@@ -131,6 +173,28 @@ module RSpec
131
173
  actual.any? { |value| values_match?(expected_item, value) }
132
174
  end
133
175
 
176
+ if RUBY_VERSION < '1.9'
177
+ def count_enumerable(expected_item)
178
+ actual.select { |value| values_match?(expected_item, value) }.size
179
+ end
180
+ else
181
+ def count_enumerable(expected_item)
182
+ actual.count { |value| values_match?(expected_item, value) }
183
+ end
184
+ end
185
+
186
+ def count_inclusions
187
+ @divergent_items = expected
188
+ case actual
189
+ when String
190
+ actual.scan(expected.first).length
191
+ when Enumerable
192
+ count_enumerable(Hash === expected ? expected : expected.first)
193
+ else
194
+ raise NotImplementedError, 'Count constraints are implemented for Enumerable and String values only'
195
+ end
196
+ end
197
+
134
198
  def diff_would_wrongly_highlight_matched_item?
135
199
  return false unless actual.is_a?(String) && expected.is_a?(Array)
136
200
 
@@ -141,7 +205,7 @@ module RSpec
141
205
  end
142
206
 
143
207
  def convert_to_hash?(obj)
144
- !(::Hash === obj) && obj.respond_to?(:to_hash)
208
+ !obj.respond_to?(:include?) && obj.respond_to?(:to_hash)
145
209
  end
146
210
  end
147
211
  end
@@ -94,6 +94,13 @@ module RSpec
94
94
  true
95
95
  end
96
96
 
97
+ # @api private
98
+ # Indicates this matcher matches against a block only.
99
+ # @return [False]
100
+ def supports_value_expectations?
101
+ false
102
+ end
103
+
97
104
  private
98
105
 
99
106
  def captured?
@@ -4,18 +4,25 @@ module RSpec
4
4
  # @api private
5
5
  # Provides the implementation for `raise_error`.
6
6
  # Not intended to be instantiated directly.
7
- # rubocop:disable ClassLength
8
- # rubocop:disable RescueException
7
+ # rubocop:disable Metrics/ClassLength
8
+ # rubocop:disable Lint/RescueException
9
9
  class RaiseError
10
10
  include Composable
11
11
 
12
- def initialize(expected_error_or_message=nil, expected_message=nil, &block)
12
+ # Used as a sentinel value to be able to tell when the user did not pass an
13
+ # argument. We can't use `nil` for that because we need to warn when `nil` is
14
+ # passed in a different way. It's an Object, not a Module, since Module's `===`
15
+ # does not evaluate to true when compared to itself.
16
+ UndefinedValue = Object.new.freeze
17
+
18
+ def initialize(expected_error_or_message, expected_message, &block)
13
19
  @block = block
14
20
  @actual_error = nil
15
- @warn_about_bare_error = expected_error_or_message.nil?
21
+ @warn_about_bare_error = UndefinedValue === expected_error_or_message
22
+ @warn_about_nil_error = expected_error_or_message.nil?
16
23
 
17
24
  case expected_error_or_message
18
- when nil
25
+ when nil, UndefinedValue
19
26
  @expected_error = Exception
20
27
  @expected_message = expected_message
21
28
  when String
@@ -36,7 +43,7 @@ module RSpec
36
43
  self
37
44
  end
38
45
 
39
- # rubocop:disable MethodLength
46
+ # rubocop:disable Metrics/MethodLength
40
47
  # @private
41
48
  def matches?(given_proc, negative_expectation=false, &block)
42
49
  @given_proc = given_proc
@@ -52,22 +59,25 @@ module RSpec
52
59
  given_proc.call
53
60
  rescue Exception => @actual_error
54
61
  if values_match?(@expected_error, @actual_error) ||
55
- values_match?(@expected_error, @actual_error.message)
62
+ values_match?(@expected_error, actual_error_message)
56
63
  @raised_expected_error = true
57
64
  @with_expected_message = verify_message
58
65
  end
59
66
  end
60
67
 
61
- warn_about_bare_error if warning_about_bare_error && !negative_expectation
62
- eval_block if !negative_expectation && ready_to_eval_block?
68
+ unless negative_expectation
69
+ warn_about_bare_error! if warn_about_bare_error?
70
+ warn_about_nil_error! if warn_about_nil_error?
71
+ eval_block if ready_to_eval_block?
72
+ end
63
73
 
64
74
  expectation_matched?
65
75
  end
66
- # rubocop:enable MethodLength
76
+ # rubocop:enable Metrics/MethodLength
67
77
 
68
78
  # @private
69
79
  def does_not_match?(given_proc)
70
- warn_for_false_positives
80
+ warn_for_negative_false_positives!
71
81
  !matches?(given_proc, :negative_expectation) && Proc === given_proc
72
82
  end
73
83
 
@@ -76,6 +86,12 @@ module RSpec
76
86
  true
77
87
  end
78
88
 
89
+ # @private
90
+ def supports_value_expectations?
91
+ false
92
+ end
93
+
94
+ # @private
79
95
  def expects_call_stack_jump?
80
96
  true
81
97
  end
@@ -83,7 +99,7 @@ module RSpec
83
99
  # @api private
84
100
  # @return [String]
85
101
  def failure_message
86
- @eval_block ? @actual_error.message : "expected #{expected_error}#{given_error}"
102
+ @eval_block ? actual_error_message : "expected #{expected_error}#{given_error}"
87
103
  end
88
104
 
89
105
  # @api private
@@ -100,6 +116,12 @@ module RSpec
100
116
 
101
117
  private
102
118
 
119
+ def actual_error_message
120
+ return nil unless @actual_error
121
+
122
+ @actual_error.respond_to?(:original_message) ? @actual_error.original_message : @actual_error.message
123
+ end
124
+
103
125
  def expectation_matched?
104
126
  error_and_message_match? && block_matches?
105
127
  end
@@ -128,32 +150,38 @@ module RSpec
128
150
 
129
151
  def verify_message
130
152
  return true if @expected_message.nil?
131
- values_match?(@expected_message, @actual_error.message.to_s)
153
+ values_match?(@expected_message, actual_error_message.to_s)
132
154
  end
133
155
 
134
- def warn_for_false_positives
156
+ def warn_for_negative_false_positives!
135
157
  expression = if expecting_specific_exception? && @expected_message
136
158
  "`expect { }.not_to raise_error(SpecificErrorClass, message)`"
137
159
  elsif expecting_specific_exception?
138
160
  "`expect { }.not_to raise_error(SpecificErrorClass)`"
139
161
  elsif @expected_message
140
162
  "`expect { }.not_to raise_error(message)`"
163
+ elsif @warn_about_nil_error
164
+ "`expect { }.not_to raise_error(nil)`"
141
165
  end
142
166
 
143
167
  return unless expression
144
168
 
145
- warn_about_negative_false_positive expression
169
+ warn_about_negative_false_positive! expression
146
170
  end
147
171
 
148
172
  def handle_warning(message)
149
173
  RSpec::Expectations.configuration.false_positives_handler.call(message)
150
174
  end
151
175
 
152
- def warning_about_bare_error
176
+ def warn_about_bare_error?
153
177
  @warn_about_bare_error && @block.nil?
154
178
  end
155
179
 
156
- def warn_about_bare_error
180
+ def warn_about_nil_error?
181
+ @warn_about_nil_error
182
+ end
183
+
184
+ def warn_about_bare_error!
157
185
  handle_warning("Using the `raise_error` matcher without providing a specific " \
158
186
  "error or message risks false positives, since `raise_error` " \
159
187
  "will match when Ruby raises a `NoMethodError`, `NameError` or " \
@@ -166,11 +194,24 @@ module RSpec
166
194
  "_positives = :nothing`")
167
195
  end
168
196
 
169
- def warn_about_negative_false_positive(expression)
197
+ def warn_about_nil_error!
198
+ handle_warning("Using the `raise_error` matcher with a `nil` error is probably " \
199
+ "unintentional, it risks false positives, since `raise_error` " \
200
+ "will match when Ruby raises a `NoMethodError`, `NameError` or " \
201
+ "`ArgumentError`, potentially allowing the expectation to pass " \
202
+ "without even executing the method you are intending to call. " \
203
+ "#{warning}"\
204
+ "Instead consider providing a specific error class or message. " \
205
+ "This message can be suppressed by setting: " \
206
+ "`RSpec::Expectations.configuration.on_potential_false" \
207
+ "_positives = :nothing`")
208
+ end
209
+
210
+ def warn_about_negative_false_positive!(expression)
170
211
  handle_warning("Using #{expression} risks false positives, since literally " \
171
212
  "any other error would cause the expectation to pass, " \
172
- "including those raised by Ruby (e.g. NoMethodError, NameError " \
173
- "and ArgumentError), meaning the code you are intending to test " \
213
+ "including those raised by Ruby (e.g. `NoMethodError`, `NameError` " \
214
+ "and `ArgumentError`), meaning the code you are intending to test " \
174
215
  "may not even get reached. Instead consider using " \
175
216
  "`expect { }.not_to raise_error` or `expect { }.to raise_error" \
176
217
  "(DifferentSpecificErrorClass)`. This message can be suppressed by " \
@@ -223,8 +264,8 @@ module RSpec
223
264
  warning if @actual_error
224
265
  end
225
266
  end
226
- # rubocop:enable RescueException
227
- # rubocop:enable ClassLength
267
+ # rubocop:enable Lint/RescueException
268
+ # rubocop:enable Metrics/ClassLength
228
269
  end
229
270
  end
230
271
  end
@@ -11,6 +11,7 @@ module RSpec
11
11
  @names = names
12
12
  @expected_arity = nil
13
13
  @expected_keywords = []
14
+ @ignoring_method_signature_failure = false
14
15
  @unlimited_arguments = nil
15
16
  @arbitrary_keywords = nil
16
17
  end
@@ -100,6 +101,12 @@ module RSpec
100
101
  "respond to #{pp_names}#{with_arity}"
101
102
  end
102
103
 
104
+ # @api private
105
+ # Used by other matchers to suppress a check
106
+ def ignoring_method_signature_failure!
107
+ @ignoring_method_signature_failure = true
108
+ end
109
+
103
110
  private
104
111
 
105
112
  def find_failing_method_names(actual, filter_method)
@@ -110,24 +117,14 @@ module RSpec
110
117
  end
111
118
 
112
119
  def matches_arity?(actual, name)
113
- expectation = Support::MethodSignatureExpectation.new
114
-
115
- if @expected_arity.is_a?(Range)
116
- expectation.min_count = @expected_arity.min
117
- expectation.max_count = @expected_arity.max
118
- else
119
- expectation.min_count = @expected_arity
120
- end
121
-
122
- expectation.keywords = @expected_keywords
123
- expectation.expect_unlimited_arguments = @unlimited_arguments
124
- expectation.expect_arbitrary_keywords = @arbitrary_keywords
125
-
126
- return true if expectation.empty?
127
-
128
- signature = Support::MethodSignature.new(Support.method_handle_for(actual, name))
129
-
130
- Support::StrictSignatureVerifier.new(signature).with_expectation(expectation).valid?
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."
131
128
  end
132
129
 
133
130
  def with_arity
@@ -159,6 +156,44 @@ module RSpec
159
156
  def pp_names
160
157
  @names.length == 1 ? "##{@names.first}" : description_of(@names)
161
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
196
+ end
162
197
  end
163
198
  end
164
199
  end
@@ -13,7 +13,7 @@ module RSpec
13
13
  @caught_symbol = @caught_arg = nil
14
14
  end
15
15
 
16
- # rubocop:disable MethodLength
16
+ # rubocop:disable Metrics/MethodLength
17
17
  # @private
18
18
  def matches?(given_proc)
19
19
  @block = given_proc
@@ -48,7 +48,7 @@ module RSpec
48
48
  rescue => other_exception
49
49
  raise
50
50
  ensure
51
- # rubocop:disable EnsureReturn
51
+ # rubocop:disable Lint/EnsureReturn
52
52
  unless other_exception
53
53
  if @expected_symbol.nil?
54
54
  return !!@caught_symbol
@@ -60,10 +60,10 @@ module RSpec
60
60
  end
61
61
  end
62
62
  end
63
- # rubocop:enable EnsureReturn
63
+ # rubocop:enable Lint/EnsureReturn
64
64
  end
65
65
  end
66
- # rubocop:enable MethodLength
66
+ # rubocop:enable Metrics/MethodLength
67
67
 
68
68
  def does_not_match?(given_proc)
69
69
  !matches?(given_proc) && Proc === given_proc
@@ -94,6 +94,12 @@ module RSpec
94
94
  true
95
95
  end
96
96
 
97
+ # @api private
98
+ def supports_value_expectations?
99
+ false
100
+ end
101
+
102
+ # @api private
97
103
  def expects_call_stack_jump?
98
104
  true
99
105
  end
@@ -1,3 +1,5 @@
1
+ require 'rspec/matchers/built_in/count_expectation'
2
+
1
3
  RSpec::Support.require_rspec_support 'method_signature_verifier'
2
4
 
3
5
  module RSpec
@@ -97,64 +99,12 @@ module RSpec
97
99
  # Provides the implementation for `yield_control`.
98
100
  # Not intended to be instantiated directly.
99
101
  class YieldControl < BaseMatcher
100
- def initialize
101
- at_least(:once)
102
- end
103
-
104
- # @api public
105
- # Specifies that the method is expected to yield once.
106
- def once
107
- exactly(1)
108
- self
109
- end
110
-
111
- # @api public
112
- # Specifies that the method is expected to yield twice.
113
- def twice
114
- exactly(2)
115
- self
116
- end
117
-
118
- # @api public
119
- # Specifies that the method is expected to yield thrice.
120
- def thrice
121
- exactly(3)
122
- self
123
- end
124
-
125
- # @api public
126
- # Specifies that the method is expected to yield the given number of times.
127
- def exactly(number)
128
- set_expected_yields_count(:==, number)
129
- self
130
- end
131
-
132
- # @api public
133
- # Specifies the maximum number of times the method is expected to yield
134
- def at_most(number)
135
- set_expected_yields_count(:<=, number)
136
- self
137
- end
138
-
139
- # @api public
140
- # Specifies the minimum number of times the method is expected to yield
141
- def at_least(number)
142
- set_expected_yields_count(:>=, number)
143
- self
144
- end
145
-
146
- # @api public
147
- # No-op. Provides syntactic sugar.
148
- def times
149
- self
150
- end
151
-
102
+ include CountExpectation
152
103
  # @private
153
104
  def matches?(block)
154
105
  @probe = YieldProbe.probe(block)
155
106
  return false unless @probe.has_block?
156
-
157
- @probe.num_yields.__send__(@expectation_type, @expected_yields_count)
107
+ expected_count_matches?(@probe.num_yields)
158
108
  end
159
109
 
160
110
  # @private
@@ -179,39 +129,17 @@ module RSpec
179
129
  true
180
130
  end
181
131
 
182
- private
183
-
184
- def set_expected_yields_count(relativity, n)
185
- @expectation_type = relativity
186
- @expected_yields_count = case n
187
- when Numeric then n
188
- when :once then 1
189
- when :twice then 2
190
- when :thrice then 3
191
- end
132
+ # @private
133
+ def supports_value_expectations?
134
+ false
192
135
  end
193
136
 
137
+ private
138
+
194
139
  def failure_reason
195
140
  return ' but was not a block' unless @probe.has_block?
196
- return '' unless @expected_yields_count
197
- " #{human_readable_expectation_type}#{human_readable_count(@expected_yields_count)}" \
198
- " but yielded #{human_readable_count(@probe.num_yields)}"
199
- end
200
-
201
- def human_readable_expectation_type
202
- case @expectation_type
203
- when :<= then 'at most '
204
- when :>= then 'at least '
205
- else ''
206
- end
207
- end
208
-
209
- def human_readable_count(count)
210
- case count
211
- when 1 then 'once'
212
- when 2 then 'twice'
213
- else "#{count} times"
214
- end
141
+ return "#{count_expectation_description} but did not yield" if @probe.num_yields == 0
142
+ count_failure_reason('yielded')
215
143
  end
216
144
  end
217
145
 
@@ -246,6 +174,11 @@ module RSpec
246
174
  true
247
175
  end
248
176
 
177
+ # @private
178
+ def supports_value_expectations?
179
+ false
180
+ end
181
+
249
182
  private
250
183
 
251
184
  def positive_failure_reason
@@ -308,6 +241,11 @@ module RSpec
308
241
  true
309
242
  end
310
243
 
244
+ # @private
245
+ def supports_value_expectations?
246
+ false
247
+ end
248
+
311
249
  private
312
250
 
313
251
  def positive_failure_reason
@@ -405,6 +343,11 @@ module RSpec
405
343
  true
406
344
  end
407
345
 
346
+ # @private
347
+ def supports_value_expectations?
348
+ false
349
+ end
350
+
408
351
  private
409
352
 
410
353
  def expected_arg_description
@@ -16,8 +16,9 @@ module RSpec
16
16
  autoload :Be, 'rspec/matchers/built_in/be'
17
17
  autoload :BeComparedTo, 'rspec/matchers/built_in/be'
18
18
  autoload :BeFalsey, 'rspec/matchers/built_in/be'
19
+ autoload :BeHelpers, 'rspec/matchers/built_in/be'
19
20
  autoload :BeNil, 'rspec/matchers/built_in/be'
20
- autoload :BePredicate, 'rspec/matchers/built_in/be'
21
+ autoload :BePredicate, 'rspec/matchers/built_in/has'
21
22
  autoload :BeTruthy, 'rspec/matchers/built_in/be'
22
23
  autoload :BeWithin, 'rspec/matchers/built_in/be_within'
23
24
  autoload :Change, 'rspec/matchers/built_in/change'