rspec-expectations 3.3.1 → 3.4.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.
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