rspec-expectations 3.3.1 → 3.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 54562bfd39d8413de176aff59a6d581cfaf424ad
4
- data.tar.gz: dbd074d06ffb583e3542f076870d82b05f3a415f
3
+ metadata.gz: ecfc9ad6573cbd51308c24b96e60534b430370e8
4
+ data.tar.gz: ee7aec158266ec8c5902def9e5777d0f47a4eb18
5
5
  SHA512:
6
- metadata.gz: ec5efa32e6fbe2d2ab77fdd6900b945c55d653466eb66ff501630f14ea2381c093ac49c66860e445af66b4aa90669e69e0747f36003cb723fc4f8b0fc76235e1
7
- data.tar.gz: 4eca41f1c7c3d84bd30bac0c4b14ffaf76f2cce9a2f7c6f5f9a4744a4e9c0a9d675dd31ab03a14c3b3848ebe6571a77514981223dd4e37ee3104a8e462bddd9d
6
+ metadata.gz: 747ae15f2866456d52996626be3ce0f131beac9c92ab447d865c052e9c6211b0eacac9f1c80d2140ef8185e6c1d3f45e88ac49d48c0b23346df325f00f84678c
7
+ data.tar.gz: 55853e5d95bf9019031a1652cf6d8b553d65ebea517b309514275faab04b66a2a713d07ab6021eb96df3d537a106d39bde239933722f2f76f236ae7518aa84a3
Binary file
data.tar.gz.sig CHANGED
Binary file
data/.document CHANGED
@@ -1,5 +1,5 @@
1
1
  lib/**/*.rb
2
2
  -
3
3
  README.md
4
- License.txt
4
+ LICENSE.md
5
5
  Changelog.md
data/.yardopts CHANGED
@@ -3,4 +3,4 @@
3
3
  --markup markdown
4
4
  -
5
5
  Changelog.md
6
- License.txt
6
+ LICENSE.md
@@ -1,3 +1,29 @@
1
+ ### 3.4.0 / 2015-11-11
2
+ [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.3.1...v3.4.0)
3
+
4
+ Enhancements:
5
+
6
+ * Warn when `RSpec::Matchers` is included in a superclass after it has
7
+ already been included in a subclass on MRI 1.9, since that situation
8
+ can cause uses of `super` to trigger infinite recursion. (Myron Marston, #816)
9
+ * Stop rescuing `NoMemoryError`, `SignalExcepetion`, `Interrupt` and
10
+ `SystemExit`. It is dangerous to interfere with these. (Myron Marston, #845)
11
+ * Add `#with_captures` to the
12
+ [match matcher](https://www.relishapp.com/rspec/rspec-expectations/docs/built-in-matchers/match-matcher)
13
+ which allows a user to specify expected captures when matching a regex
14
+ against a string. (Sam Phippen, #848)
15
+ * Always print compound failure messages in the multi-line form. Trying
16
+ to print it all on a single line didn't read very well. (Myron Marston, #859)
17
+
18
+ Bug Fixes:
19
+
20
+ * Fix failure message from dynamic predicate matchers when the object
21
+ does not respond to the predicate so that it is inspected rather
22
+ than relying upon it's `to_s` -- that way for `nil`, `"nil"` is
23
+ printed rather than an empty string. (Myron Marston, #841)
24
+ * Fix SystemStackError raised when diffing an Enumerable object
25
+ whose `#each` includes the object itself. (Yuji Nakayama, #857)
26
+
1
27
  ### 3.3.1 / 2015-07-15
2
28
  [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.3.0...v3.3.1)
3
29
 
@@ -1,8 +1,9 @@
1
- (The MIT License)
1
+ The MIT License (MIT)
2
+ =====================
2
3
 
3
- Copyright (c) 2012 David Chelimsky, Myron Marston
4
- Copyright (c) 2006 David Chelimsky, The RSpec Development Team
5
- Copyright (c) 2005 Steven Baker
4
+ * Copyright © 2012 David Chelimsky, Myron Marston
5
+ * Copyright © 2006 David Chelimsky, The RSpec Development Team
6
+ * Copyright © 2005 Steven Baker
6
7
 
7
8
  Permission is hereby granted, free of charge, to any person obtaining
8
9
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -27,6 +27,20 @@ Minitest, or Cucumber, you can install it directly:
27
27
 
28
28
  gem install rspec-expectations
29
29
 
30
+ ## Contributing
31
+
32
+ Once you've set up the environment, you'll need to cd into the working
33
+ directory of whichever repo you want to work in. From there you can run the
34
+ specs and cucumber features, and make patches.
35
+
36
+ NOTE: You do not need to use rspec-dev to work on a specific RSpec repo. You
37
+ can treat each RSpec repo as an independent project.
38
+
39
+ - [Build details](BUILD_DETAIL.md)
40
+ - [Code of Conduct](CODE_OF_CONDUCT.md)
41
+ - [Detailed contributing guide](CONTRIBUTING.md)
42
+ - [Development setup guide](DEVELOPMENT.md)
43
+
30
44
  ## Basic usage
31
45
 
32
46
  Here's an example using rspec-core:
@@ -283,7 +297,7 @@ end
283
297
 
284
298
  ## Also see
285
299
 
286
- * [http://github.com/rspec/rspec](http://github.com/rspec/rspec)
287
- * [http://github.com/rspec/rspec-core](http://github.com/rspec/rspec-core)
288
- * [http://github.com/rspec/rspec-mocks](http://github.com/rspec/rspec-mocks)
289
- * [http://github.com/rspec/rspec-collection_matchers](https://github.com/rspec/rspec-collection_matchers)
300
+ * [https://github.com/rspec/rspec](https://github.com/rspec/rspec)
301
+ * [https://github.com/rspec/rspec-core](https://github.com/rspec/rspec-core)
302
+ * [https://github.com/rspec/rspec-mocks](https://github.com/rspec/rspec-mocks)
303
+ * [https://github.com/rspec/rspec-rails](https://github.com/rspec/rspec-rails)
@@ -15,7 +15,7 @@ module RSpec
15
15
  # of `failures` rather than letting it fall through and be categorized as part of
16
16
  # `other_errors`.
17
17
  failures << e
18
- rescue Exception => e
18
+ rescue Support::AllExceptionsExceptOnesWeMustNotRescue => e
19
19
  # While it is normally a bad practice to rescue `Exception`, it's important we do
20
20
  # so here. It's low risk (`notify_aggregated_failures` below will re-raise the exception,
21
21
  # or raise a `MultipleExpectationsNotMetError` that includes the exception), and it's
@@ -2,7 +2,7 @@ module RSpec
2
2
  module Expectations
3
3
  # @private
4
4
  module Version
5
- STRING = '3.3.1'
5
+ STRING = '3.4.0'
6
6
  end
7
7
  end
8
8
  end
@@ -1005,5 +1005,33 @@ module RSpec
1005
1005
  def self.is_a_describable_matcher?(obj)
1006
1006
  is_a_matcher?(obj) && obj.respond_to?(:description)
1007
1007
  end
1008
+
1009
+ if RSpec::Support::Ruby.mri? && RUBY_VERSION[0, 3] == '1.9'
1010
+ # @api private
1011
+ # Note that `included` doesn't work for this because it is triggered
1012
+ # _after_ `RSpec::Matchers` is an ancestor of the inclusion host, rather
1013
+ # than _before_, like `append_features`. It's important we check this before
1014
+ # in order to find the cases where it was already previously included.
1015
+ def self.append_features(mod)
1016
+ return super if mod < self # `mod < self` indicates a re-inclusion.
1017
+
1018
+ subclasses = ObjectSpace.each_object(Class).select { |c| c < mod && c < self }
1019
+ return super unless subclasses.any?
1020
+
1021
+ subclasses.reject! { |s| subclasses.any? { |s2| s < s2 } } # Filter to the root ancestor.
1022
+ subclasses = subclasses.map { |s| "`#{s}`" }.join(", ")
1023
+
1024
+ RSpec.warning "`#{self}` has been included in a superclass (`#{mod}`) " \
1025
+ "after previously being included in subclasses (#{subclasses}), " \
1026
+ "which can trigger infinite recursion from `super` due to an MRI 1.9 bug " \
1027
+ "(https://redmine.ruby-lang.org/issues/3351). To work around this, " \
1028
+ "either upgrade to MRI 2.0+, include a dup of the module (e.g. " \
1029
+ "`include #{self}.dup`), or find a way to include `#{self}` in `#{mod}` " \
1030
+ "before it is included in subclasses (#{subclasses}). See " \
1031
+ "https://github.com/rspec/rspec-expectations/issues/814 for more info"
1032
+
1033
+ super
1034
+ end
1035
+ end
1008
1036
  end
1009
1037
  end
@@ -8,8 +8,8 @@ module RSpec
8
8
  #
9
9
  # ### Warning:
10
10
  #
11
- # This class is for internal use, and subject to change without notice. We
12
- # strongly recommend that you do not base your custom matchers on this
11
+ # This class is for internal use, and subject to change without notice.
12
+ # We strongly recommend that you do not base your custom matchers on this
13
13
  # class. If/when this changes, we will announce it and remove this warning.
14
14
  class BaseMatcher
15
15
  include RSpec::Matchers::Composable
@@ -92,7 +92,7 @@ module RSpec
92
92
 
93
93
  # @private
94
94
  def self.matcher_name
95
- @matcher_name ||= underscore(name.split("::").last)
95
+ @matcher_name ||= underscore(name.split('::').last)
96
96
  end
97
97
 
98
98
  # @private
@@ -101,7 +101,7 @@ module RSpec
101
101
  word = camel_cased_word.to_s.dup
102
102
  word.gsub!(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
103
103
  word.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
104
- word.tr!("-", "_")
104
+ word.tr!('-', '_')
105
105
  word.downcase!
106
106
  word
107
107
  end
@@ -118,7 +118,7 @@ module RSpec
118
118
  if RUBY_VERSION.to_f < 1.9
119
119
  # :nocov:
120
120
  def present_ivars
121
- instance_variables.map { |v| v.to_sym }
121
+ instance_variables.map(&:to_sym)
122
122
  end
123
123
  # :nocov:
124
124
  else
@@ -168,7 +168,7 @@ module RSpec
168
168
  # @private
169
169
  def self.has_default_failure_messages?(matcher)
170
170
  matcher.method(:failure_message).owner == self &&
171
- matcher.method(:failure_message_when_negated).owner == self
171
+ matcher.method(:failure_message_when_negated).owner == self
172
172
  rescue NameError
173
173
  false
174
174
  end
@@ -267,7 +267,7 @@ module RSpec
267
267
  def validity_message
268
268
  return nil if predicate_accessible?
269
269
 
270
- msg = "expected #{@actual} to respond to `#{predicate}`"
270
+ msg = "expected #{actual_formatted} to respond to `#{predicate}`"
271
271
 
272
272
  if private_predicate?
273
273
  msg << " but `#{predicate}` is a private method"
@@ -58,13 +58,15 @@ module RSpec
58
58
  # @api private
59
59
  # @return [String]
60
60
  def failure_message
61
- "expected #{@change_details.message} to have changed, but #{positive_failure_reason}"
61
+ "expected #{@change_details.message} to have changed, " \
62
+ "but #{positive_failure_reason}"
62
63
  end
63
64
 
64
65
  # @api private
65
66
  # @return [String]
66
67
  def failure_message_when_negated
67
- "expected #{@change_details.message} not to have changed, but #{negative_failure_reason}"
68
+ "expected #{@change_details.message} not to have changed, " \
69
+ "but #{negative_failure_reason}"
68
70
  end
69
71
 
70
72
  # @api private
@@ -96,7 +98,8 @@ module RSpec
96
98
 
97
99
  def negative_failure_reason
98
100
  return "was not given a block" unless Proc === @event_proc
99
- "did change from #{description_of @change_details.actual_before} to #{description_of @change_details.actual_after}"
101
+ "did change from #{description_of @change_details.actual_before} " \
102
+ "to #{description_of @change_details.actual_after}"
100
103
  end
101
104
  end
102
105
 
@@ -112,7 +115,9 @@ module RSpec
112
115
 
113
116
  # @private
114
117
  def failure_message
115
- "expected #{@change_details.message} to have changed #{@relativity.to_s.gsub("_", " ")} #{description_of @expected_delta}, but #{failure_reason}"
118
+ "expected #{@change_details.message} to have changed " \
119
+ "#{@relativity.to_s.tr('_', ' ')} " \
120
+ "#{description_of @expected_delta}, but #{failure_reason}"
116
121
  end
117
122
 
118
123
  # @private
@@ -125,12 +130,14 @@ module RSpec
125
130
 
126
131
  # @private
127
132
  def does_not_match?(_event_proc)
128
- raise NotImplementedError, "`expect { }.not_to change { }.#{@relativity}()` is not supported"
133
+ raise NotImplementedError, "`expect { }.not_to change " \
134
+ "{ }.#{@relativity}()` is not supported"
129
135
  end
130
136
 
131
137
  # @private
132
138
  def description
133
- "change #{@change_details.message} #{@relativity.to_s.gsub("_", " ")} #{description_of @expected_delta}"
139
+ "change #{@change_details.message} " \
140
+ "#{@relativity.to_s.tr('_', ' ')} #{description_of @expected_delta}"
134
141
  end
135
142
 
136
143
  # @private
@@ -195,23 +202,31 @@ module RSpec
195
202
  end
196
203
 
197
204
  def before_value_failure
198
- "expected #{@change_details.message} to have initially been #{description_of @expected_before}, but was #{description_of @change_details.actual_before}"
205
+ "expected #{@change_details.message} " \
206
+ "to have initially been #{description_of @expected_before}, " \
207
+ "but was #{description_of @change_details.actual_before}"
199
208
  end
200
209
 
201
210
  def after_value_failure
202
- "expected #{@change_details.message} to have changed to #{description_of @expected_after}, but is now #{description_of @change_details.actual_after}"
211
+ "expected #{@change_details.message} " \
212
+ "to have changed to #{description_of @expected_after}, " \
213
+ "but is now #{description_of @change_details.actual_after}"
203
214
  end
204
215
 
205
216
  def did_not_change_failure
206
- "expected #{@change_details.message} to have changed #{change_description}, but did not change"
217
+ "expected #{@change_details.message} " \
218
+ "to have changed #{change_description}, but did not change"
207
219
  end
208
220
 
209
221
  def did_change_failure
210
- "expected #{@change_details.message} not to have changed, but did change from #{description_of @change_details.actual_before} to #{description_of @change_details.actual_after}"
222
+ "expected #{@change_details.message} not to have changed, but " \
223
+ "did change from #{description_of @change_details.actual_before} " \
224
+ "to #{description_of @change_details.actual_after}"
211
225
  end
212
226
 
213
227
  def not_given_a_block_failure
214
- "expected #{@change_details.message} to have changed #{change_description}, but was not given a block"
228
+ "expected #{@change_details.message} to have changed " \
229
+ "#{change_description}, but was not given a block"
215
230
  end
216
231
  end
217
232
 
@@ -235,7 +250,8 @@ module RSpec
235
250
  # @private
236
251
  def does_not_match?(event_proc)
237
252
  if @description_suffix
238
- raise NotImplementedError, "`expect { }.not_to change { }.to()` is not supported"
253
+ raise NotImplementedError, "`expect { }.not_to change { }.to()` " \
254
+ "is not supported"
239
255
  end
240
256
 
241
257
  @event_proc = event_proc
@@ -277,7 +293,8 @@ module RSpec
277
293
 
278
294
  # @private
279
295
  def does_not_match?(_event_proc)
280
- raise NotImplementedError, "`expect { }.not_to change { }.to()` is not supported"
296
+ raise NotImplementedError, "`expect { }.not_to change { }.to()` " \
297
+ "is not supported"
281
298
  end
282
299
 
283
300
  private
@@ -24,7 +24,7 @@ module RSpec
24
24
  # @api private
25
25
  # @return [String]
26
26
  def description
27
- singleline_message(matcher_1.description, matcher_2.description)
27
+ "#{matcher_1.description} #{conjunction} #{matcher_2.description}"
28
28
  end
29
29
 
30
30
  def supports_block_expectations?
@@ -84,30 +84,9 @@ module RSpec
84
84
  end
85
85
 
86
86
  def compound_failure_message
87
- message_1 = matcher_1.failure_message
88
- message_2 = matcher_2.failure_message
89
-
90
- if multiline?(message_1) || multiline?(message_2)
91
- multiline_message(message_1, message_2)
92
- else
93
- singleline_message(message_1, message_2)
94
- end
95
- end
96
-
97
- def multiline_message(message_1, message_2)
98
- [
99
- indent_multiline_message(message_1.sub(/\n+\z/, '')),
100
- "...#{conjunction}:",
101
- indent_multiline_message(message_2.sub(/\A\n+/, ''))
102
- ].join("\n\n")
103
- end
104
-
105
- def multiline?(message)
106
- message.lines.count > 1
107
- end
108
-
109
- def singleline_message(message_1, message_2)
110
- [message_1, conjunction, message_2].join(' ')
87
+ "#{indent_multiline_message(matcher_1.failure_message.sub(/\n+\z/, ''))}" \
88
+ "\n\n...#{conjunction}:" \
89
+ "\n\n#{indent_multiline_message(matcher_2.failure_message.sub(/\A\n+/, ''))}"
111
90
  end
112
91
 
113
92
  def matcher_1_matches?
@@ -9,11 +9,7 @@ module RSpec
9
9
  # @return [String]
10
10
  def failure_message
11
11
  if Array === actual
12
- message = "expected collection contained: #{description_of(safe_sort(surface_descriptions_in expected))}\n"
13
- message += "actual collection contained: #{description_of(safe_sort(actual))}\n"
14
- message += "the missing elements were: #{description_of(safe_sort(surface_descriptions_in missing_items))}\n" unless missing_items.empty?
15
- message += "the extra elements were: #{description_of(safe_sort(extra_items))}\n" unless extra_items.empty?
16
- message
12
+ generate_failure_message
17
13
  else
18
14
  "expected a collection that can be converted to an array with " \
19
15
  "`#to_ary` or `#to_a`, but got #{actual_formatted}"
@@ -36,6 +32,43 @@ module RSpec
36
32
 
37
33
  private
38
34
 
35
+ def generate_failure_message
36
+ message = expected_collection_line
37
+ message += actual_collection_line
38
+ message += missing_elements_line unless missing_items.empty?
39
+ message += extra_elements_line unless extra_items.empty?
40
+ message
41
+ end
42
+
43
+ def expected_collection_line
44
+ message_line('expected collection contained', expected, true)
45
+ end
46
+
47
+ def actual_collection_line
48
+ message_line('actual collection contained', actual)
49
+ end
50
+
51
+ def missing_elements_line
52
+ message_line('the missing elements were', missing_items, true)
53
+ end
54
+
55
+ def extra_elements_line
56
+ message_line('the extra elements were', extra_items)
57
+ end
58
+
59
+ def describe_collection(collection, surface_descriptions=false)
60
+ if surface_descriptions
61
+ "#{description_of(safe_sort(surface_descriptions_in collection))}\n"
62
+ else
63
+ "#{description_of(safe_sort(collection))}\n"
64
+ end
65
+ end
66
+
67
+ def message_line(prefix, collection, surface_descriptions=false)
68
+ "%-32s%s" % [prefix + ':',
69
+ describe_collection(collection, surface_descriptions)]
70
+ end
71
+
39
72
  def match(_expected, _actual)
40
73
  return false unless convert_actual_to_an_array
41
74
  match_when_sorted? || (extra_items.empty? && missing_items.empty?)
@@ -61,7 +94,7 @@ module RSpec
61
94
 
62
95
  def safe_sort(array)
63
96
  array.sort
64
- rescue Exception
97
+ rescue Support::AllExceptionsExceptOnesWeMustNotRescue
65
98
  array
66
99
  end
67
100
 
@@ -231,7 +264,7 @@ module RSpec
231
264
 
232
265
  modified_expecteds.delete(expected_index)
233
266
 
234
- modified_actuals = apply_pairing_to(
267
+ modified_actuals = apply_pairing_to(
235
268
  solution.indeterminate_actual_indexes,
236
269
  actual_to_expected_matched_indexes, expected_index)
237
270
 
@@ -5,10 +5,19 @@ module RSpec
5
5
  # Provides the implementation for `match`.
6
6
  # Not intended to be instantiated directly.
7
7
  class Match < BaseMatcher
8
+ def initialize(expected)
9
+ super(expected)
10
+
11
+ @expected_captures = nil
12
+ end
8
13
  # @api private
9
14
  # @return [String]
10
15
  def description
11
- "match #{surface_descriptions_in(expected).inspect}"
16
+ if @expected_captures && @expected.match(actual)
17
+ "match #{surface_descriptions_in(expected).inspect} with captures #{surface_descriptions_in(@expected_captures).inspect}"
18
+ else
19
+ "match #{surface_descriptions_in(expected).inspect}"
20
+ end
12
21
  end
13
22
 
14
23
  # @api private
@@ -17,9 +26,17 @@ module RSpec
17
26
  true
18
27
  end
19
28
 
29
+ # Used to specify the captures we match against
30
+ # @return [self]
31
+ def with_captures(*captures)
32
+ @expected_captures = captures
33
+ self
34
+ end
35
+
20
36
  private
21
37
 
22
38
  def match(expected, actual)
39
+ return match_captures(expected, actual) if @expected_captures
23
40
  return true if values_match?(expected, actual)
24
41
  return false unless can_safely_call_match?(expected, actual)
25
42
  actual.match(expected)
@@ -31,6 +48,58 @@ module RSpec
31
48
  !(RSpec::Matchers.is_a_matcher?(expected) &&
32
49
  (String === actual || Regexp === actual))
33
50
  end
51
+
52
+ def match_captures(expected, actual)
53
+ match = actual.match(expected)
54
+ if match
55
+ match = ReliableMatchData.new(match)
56
+ if match.names.empty?
57
+ values_match?(@expected_captures, match.captures)
58
+ else
59
+ expected_matcher = @expected_captures.last
60
+ values_match?(expected_matcher, Hash[match.names.zip(match.captures)]) ||
61
+ values_match?(expected_matcher, Hash[match.names.map(&:to_sym).zip(match.captures)]) ||
62
+ values_match?(@expected_captures, match.captures)
63
+ end
64
+ else
65
+ false
66
+ end
67
+ end
68
+ end
69
+
70
+ # @api private
71
+ # Used to wrap match data and make it reliable for 1.8.7
72
+ class ReliableMatchData
73
+ def initialize(match_data)
74
+ @match_data = match_data
75
+ end
76
+
77
+ if RUBY_VERSION == "1.8.7"
78
+ # @api private
79
+ # Returns match data names for named captures
80
+ # @return Array
81
+ def names
82
+ []
83
+ end
84
+ else
85
+ # @api private
86
+ # Returns match data names for named captures
87
+ # @return Array
88
+ def names
89
+ match_data.names
90
+ end
91
+ end
92
+
93
+ # @api private
94
+ # returns an array of captures from the match data
95
+ # @return Array
96
+ def captures
97
+ match_data.captures
98
+ end
99
+
100
+ protected
101
+
102
+ attr_reader :match_data
34
103
  end
35
104
  end
36
105
  end
@@ -5,6 +5,7 @@ module RSpec
5
5
  # Provides the implementation for `raise_error`.
6
6
  # Not intended to be instantiated directly.
7
7
  # rubocop:disable ClassLength
8
+ # rubocop:disable RescueException
8
9
  class RaiseError
9
10
  include Composable
10
11
 
@@ -15,11 +16,14 @@ module RSpec
15
16
 
16
17
  case expected_error_or_message
17
18
  when nil
18
- @expected_error, @expected_message = Exception, expected_message
19
+ @expected_error = Exception
20
+ @expected_message = expected_message
19
21
  when String
20
- @expected_error, @expected_message = Exception, expected_error_or_message
22
+ @expected_error = Exception
23
+ @expected_message = expected_error_or_message
21
24
  else
22
- @expected_error, @expected_message = expected_error_or_message, expected_message
25
+ @expected_error = expected_error_or_message
26
+ @expected_message = expected_message
23
27
  end
24
28
  end
25
29
 
@@ -42,7 +46,6 @@ module RSpec
42
46
  @eval_block = false
43
47
  @eval_block_passed = false
44
48
 
45
- warn_about_bare_error if warning_about_bare_error && !negative_expectation
46
49
  return false unless Proc === given_proc
47
50
 
48
51
  begin
@@ -55,6 +58,7 @@ module RSpec
55
58
  end
56
59
  end
57
60
 
61
+ warn_about_bare_error if warning_about_bare_error && !negative_expectation
58
62
  eval_block if !negative_expectation && ready_to_eval_block?
59
63
 
60
64
  expectation_matched?
@@ -156,6 +160,7 @@ module RSpec
156
160
  "will match when Ruby raises a `NoMethodError`, `NameError` or " \
157
161
  "`ArgumentError`, potentially allowing the expectation to pass " \
158
162
  "without even executing the method you are intending to call. " \
163
+ "#{warning}"\
159
164
  "Instead consider providing a specific error class or message. " \
160
165
  "This message can be supressed by setting: " \
161
166
  "`RSpec::Expectations.configuration.warn_about_potential_false_positives = false`")
@@ -207,9 +212,16 @@ module RSpec
207
212
  end
208
213
 
209
214
  def raise_message_already_set
210
- raise "`expect { }.to raise_error(message).with_message(message)` is not valid. The matcher only allows the expected message to be specified once"
215
+ raise "`expect { }.to raise_error(message).with_message(message)` is not valid. " \
216
+ 'The matcher only allows the expected message to be specified once'
217
+ end
218
+
219
+ def warning
220
+ warning = "Actual error raised was #{description_of(@actual_error)}. "
221
+ warning if @actual_error
211
222
  end
212
223
  end
224
+ # rubocop:enable RescueException
213
225
  # rubocop:enable ClassLength
214
226
  end
215
227
  end
@@ -1,4 +1,4 @@
1
- RSpec::Support.require_rspec_support "method_signature_verifier"
1
+ RSpec::Support.require_rspec_support 'method_signature_verifier'
2
2
 
3
3
  module RSpec
4
4
  module Matchers
@@ -22,7 +22,8 @@ module RSpec
22
22
  def initialize(block)
23
23
  @block = block
24
24
  @used = false
25
- self.num_yields, self.yielded_args = 0, []
25
+ self.num_yields = 0
26
+ self.yielded_args = []
26
27
  end
27
28
 
28
29
  def has_block?
@@ -50,8 +51,8 @@ module RSpec
50
51
  when 0 then false
51
52
  else
52
53
  raise "The #{matcher_name} matcher is not designed to be used with a " \
53
- "method that yields multiple times. Use the yield_successive_args " \
54
- "matcher for that case."
54
+ 'method that yields multiple times. Use the yield_successive_args ' \
55
+ 'matcher for that case.'
55
56
  end
56
57
  end
57
58
 
@@ -63,19 +64,19 @@ module RSpec
63
64
 
64
65
  def assert_used!
65
66
  return if @used
66
- raise "You must pass the argument yielded to your expect block on " \
67
- "to the method-under-test as a block. It acts as a probe that " \
68
- "allows the matcher to detect whether or not the method-under-test " \
69
- "yields, and, if so, how many times, and what the yielded arguments " \
70
- "are."
67
+ raise 'You must pass the argument yielded to your expect block on ' \
68
+ 'to the method-under-test as a block. It acts as a probe that ' \
69
+ 'allows the matcher to detect whether or not the method-under-test ' \
70
+ 'yields, and, if so, how many times, and what the yielded arguments ' \
71
+ 'are.'
71
72
  end
72
73
 
73
74
  if RUBY_VERSION.to_f > 1.8
74
75
  def assert_valid_expect_block!
75
76
  block_signature = RSpec::Support::BlockSignature.new(@block)
76
77
  return if RSpec::Support::StrictSignatureVerifier.new(block_signature, [self]).valid?
77
- raise "Your expect block must accept an argument to be used with this " \
78
- "matcher. Pass the argument as a block on to the method you are testing."
78
+ raise 'Your expect block must accept an argument to be used with this ' \
79
+ 'matcher. Pass the argument as a block on to the method you are testing.'
79
80
  end
80
81
  else
81
82
  # :nocov:
@@ -190,7 +191,7 @@ module RSpec
190
191
  end
191
192
 
192
193
  def failure_reason
193
- return " but was not a block" unless @probe.has_block?
194
+ return ' but was not a block' unless @probe.has_block?
194
195
  return '' unless @expected_yields_count
195
196
  " #{human_readable_expectation_type}#{human_readable_count(@expected_yields_count)}" \
196
197
  " but yielded #{human_readable_count(@probe.num_yields)}"
@@ -206,8 +207,8 @@ module RSpec
206
207
 
207
208
  def human_readable_count(count)
208
209
  case count
209
- when 1 then "once"
210
- when 2 then "twice"
210
+ when 1 then 'once'
211
+ when 2 then 'twice'
211
212
  else "#{count} times"
212
213
  end
213
214
  end
@@ -247,14 +248,14 @@ module RSpec
247
248
  private
248
249
 
249
250
  def positive_failure_reason
250
- return "was not a block" unless @probe.has_block?
251
- return "did not yield" if @probe.num_yields.zero?
251
+ return 'was not a block' unless @probe.has_block?
252
+ return 'did not yield' if @probe.num_yields.zero?
252
253
  "yielded with arguments: #{description_of @probe.single_yield_args}"
253
254
  end
254
255
 
255
256
  def negative_failure_reason
256
- return "was not a block" unless @probe.has_block?
257
- "did"
257
+ return 'was not a block' unless @probe.has_block?
258
+ 'did'
258
259
  end
259
260
  end
260
261
 
@@ -291,7 +292,7 @@ module RSpec
291
292
 
292
293
  # @private
293
294
  def description
294
- desc = "yield with args"
295
+ desc = 'yield with args'
295
296
  desc << "(#{expected_arg_description})" unless @expected.empty?
296
297
  desc
297
298
  end
@@ -304,36 +305,36 @@ module RSpec
304
305
  private
305
306
 
306
307
  def positive_failure_reason
307
- return "was not a block" unless @probe.has_block?
308
- return "did not yield" if @probe.num_yields.zero?
308
+ return 'was not a block' unless @probe.has_block?
309
+ return 'did not yield' if @probe.num_yields.zero?
309
310
  @positive_args_failure
310
311
  end
311
312
 
312
313
  def expected_arg_description
313
- @expected.map { |e| description_of e }.join(", ")
314
+ @expected.map { |e| description_of e }.join(', ')
314
315
  end
315
316
 
316
317
  def negative_failure_reason
317
318
  if !@probe.has_block?
318
- "was not a block"
319
+ 'was not a block'
319
320
  elsif all_args_match?
320
- "yielded with expected arguments" \
321
- "\nexpected not: #{surface_descriptions_in(@expected).inspect}" +
321
+ 'yielded with expected arguments' \
322
+ "\nexpected not: #{surface_descriptions_in(@expected).inspect}" \
322
323
  "\n got: #{actual_formatted}"
323
324
  else
324
- "did"
325
+ 'did'
325
326
  end
326
327
  end
327
328
 
328
329
  def args_match?
329
330
  if @expected.empty? # expect {...}.to yield_with_args
330
- @positive_args_failure = "yielded with no arguments" if @actual.empty?
331
+ @positive_args_failure = 'yielded with no arguments' if @actual.empty?
331
332
  return !@actual.empty?
332
333
  end
333
334
 
334
335
  unless (match = all_args_match?)
335
- @positive_args_failure = "yielded with unexpected arguments" \
336
- "\nexpected: #{surface_descriptions_in(@expected).inspect}" +
336
+ @positive_args_failure = 'yielded with unexpected arguments' \
337
+ "\nexpected: #{surface_descriptions_in(@expected).inspect}" \
337
338
  "\n got: #{actual_formatted}"
338
339
  end
339
340
 
@@ -367,19 +368,19 @@ module RSpec
367
368
 
368
369
  # @private
369
370
  def failure_message
370
- "expected given block to yield successively with arguments, but #{positive_failure_reason}"
371
+ 'expected given block to yield successively with arguments, ' \
372
+ "but #{positive_failure_reason}"
371
373
  end
372
374
 
373
375
  # @private
374
376
  def failure_message_when_negated
375
- "expected given block not to yield successively with arguments, but #{negative_failure_reason}"
377
+ 'expected given block not to yield successively with arguments, ' \
378
+ "but #{negative_failure_reason}"
376
379
  end
377
380
 
378
381
  # @private
379
382
  def description
380
- desc = "yield successive args"
381
- desc << "(#{expected_arg_description})"
382
- desc
383
+ "yield successive args(#{expected_arg_description})"
383
384
  end
384
385
 
385
386
  # @private
@@ -394,21 +395,21 @@ module RSpec
394
395
  end
395
396
 
396
397
  def expected_arg_description
397
- @expected.map { |e| description_of e }.join(", ")
398
+ @expected.map { |e| description_of e }.join(', ')
398
399
  end
399
400
 
400
401
  def positive_failure_reason
401
- return "was not a block" unless @probe.has_block?
402
+ return 'was not a block' unless @probe.has_block?
402
403
 
403
- "yielded with unexpected arguments" \
404
+ 'yielded with unexpected arguments' \
404
405
  "\nexpected: #{surface_descriptions_in(@expected).inspect}" \
405
406
  "\n got: #{actual_formatted}"
406
407
  end
407
408
 
408
409
  def negative_failure_reason
409
- return "was not a block" unless @probe.has_block?
410
+ return 'was not a block' unless @probe.has_block?
410
411
 
411
- "yielded with expected arguments" \
412
+ 'yielded with expected arguments' \
412
413
  "\nexpected not: #{surface_descriptions_in(@expected).inspect}" \
413
414
  "\n got: #{actual_formatted}"
414
415
  end
@@ -100,14 +100,10 @@ module RSpec
100
100
  DescribableItem.new(item)
101
101
  elsif Hash === item
102
102
  Hash[surface_descriptions_in(item.to_a)]
103
- elsif Struct === item
103
+ elsif Struct === item || unreadable_io?(item)
104
104
  RSpec::Support::ObjectFormatter.format(item)
105
105
  elsif should_enumerate?(item)
106
- begin
107
- item.map { |subitem| surface_descriptions_in(subitem) }
108
- rescue IOError # STDOUT is enumerable but `map` raises an error
109
- RSpec::Support::ObjectFormatter.format(item)
110
- end
106
+ item.map { |subitem| surface_descriptions_in(subitem) }
111
107
  else
112
108
  item
113
109
  end
@@ -134,14 +130,10 @@ module RSpec
134
130
  object.clone
135
131
  elsif Hash === object
136
132
  Hash[with_matchers_cloned(object.to_a)]
137
- elsif Struct === object
133
+ elsif Struct === object || unreadable_io?(object)
138
134
  object
139
135
  elsif should_enumerate?(object)
140
- begin
141
- object.map { |subobject| with_matchers_cloned(subobject) }
142
- rescue IOError # STDOUT is enumerable but `map` raises an error
143
- object
144
- end
136
+ object.map { |subobject| with_matchers_cloned(subobject) }
145
137
  else
146
138
  object
147
139
  end
@@ -157,16 +149,25 @@ module RSpec
157
149
  # @api private
158
150
  def should_enumerate?(item)
159
151
  return false if String === item
160
- Enumerable === item && !(Range === item)
152
+ Enumerable === item && !(Range === item) && item.none? { |subitem| subitem.equal?(item) }
161
153
  end
162
154
  # :nocov:
163
155
  else
164
156
  # @api private
165
157
  def should_enumerate?(item)
166
- Enumerable === item && !(Range === item)
158
+ Enumerable === item && !(Range === item) && item.none? { |subitem| subitem.equal?(item) }
167
159
  end
168
160
  end
169
- module_function :surface_descriptions_in, :should_enumerate?
161
+
162
+ # @api private
163
+ def unreadable_io?(object)
164
+ return false unless IO === object
165
+ object.each {} # STDOUT is enumerable but raises an error
166
+ false
167
+ rescue IOError
168
+ true
169
+ end
170
+ module_function :surface_descriptions_in, :should_enumerate?, :unreadable_io?
170
171
 
171
172
  # Wraps an item in order to surface its `description` via `inspect`.
172
173
  # @api private
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspec-expectations
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.3.1
4
+ version: 3.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steven Baker
@@ -45,7 +45,7 @@ cert_chain:
45
45
  ZsVDj6a7lH3cNqtWXZxrb2wO38qV5AkYj8SQK7Hj3/Yui9myUX3crr+PdetazSqQ
46
46
  F3MdtaDehhjC
47
47
  -----END CERTIFICATE-----
48
- date: 2015-07-15 00:00:00.000000000 Z
48
+ date: 2015-11-12 00:00:00.000000000 Z
49
49
  dependencies:
50
50
  - !ruby/object:Gem::Dependency
51
51
  name: rspec-support
@@ -53,14 +53,14 @@ dependencies:
53
53
  requirements:
54
54
  - - "~>"
55
55
  - !ruby/object:Gem::Version
56
- version: 3.3.0
56
+ version: 3.4.0
57
57
  type: :runtime
58
58
  prerelease: false
59
59
  version_requirements: !ruby/object:Gem::Requirement
60
60
  requirements:
61
61
  - - "~>"
62
62
  - !ruby/object:Gem::Version
63
- version: 3.3.0
63
+ version: 3.4.0
64
64
  - !ruby/object:Gem::Dependency
65
65
  name: diff-lcs
66
66
  requirement: !ruby/object:Gem::Requirement
@@ -115,14 +115,14 @@ dependencies:
115
115
  requirements:
116
116
  - - "~>"
117
117
  - !ruby/object:Gem::Version
118
- version: '0.6'
118
+ version: 0.6.2
119
119
  type: :development
120
120
  prerelease: false
121
121
  version_requirements: !ruby/object:Gem::Requirement
122
122
  requirements:
123
123
  - - "~>"
124
124
  - !ruby/object:Gem::Version
125
- version: '0.6'
125
+ version: 0.6.2
126
126
  - !ruby/object:Gem::Dependency
127
127
  name: minitest
128
128
  requirement: !ruby/object:Gem::Requirement
@@ -147,7 +147,7 @@ files:
147
147
  - ".document"
148
148
  - ".yardopts"
149
149
  - Changelog.md
150
- - License.txt
150
+ - LICENSE.md
151
151
  - README.md
152
152
  - lib/rspec/expectations.rb
153
153
  - lib/rspec/expectations/configuration.rb
@@ -220,6 +220,6 @@ rubyforge_project:
220
220
  rubygems_version: 2.2.2
221
221
  signing_key:
222
222
  specification_version: 4
223
- summary: rspec-expectations-3.3.1
223
+ summary: rspec-expectations-3.4.0
224
224
  test_files: []
225
225
  has_rdoc:
metadata.gz.sig CHANGED
Binary file