rspec-expectations 3.7.0 → 3.8.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: 4d5dd8b33952790fa1f2558ff0e899938b2e3cab
4
- data.tar.gz: b54c4711b21c2865f50be1a44fdf1b52b8cb0b36
3
+ metadata.gz: c64b53ac0865670b12407e85b12dfef41a915675
4
+ data.tar.gz: 72290b7d0bfa0774d0a75ba08c9c4f87b3684e9b
5
5
  SHA512:
6
- metadata.gz: f7fa51873f771382abdf2731b0862510514a8110985b24ca0e5f33ab2e93cd81e06481c8f82d83e806daa0cd2d6325db62e04290274be6c252c5eaf8599dcd70
7
- data.tar.gz: 4823b182ad808801c9a0aa9e8aa97cff18221e0e8bb7c77241fb807af96fa5fb6f68ad026a68338d2f0122bc479ee78cf650c5d2dfdfc034439983175973302f
6
+ metadata.gz: 9c98a819df168dca33a9a74275a8b8034d7670c22e9bf40cfa4c4e483fe0c78d1aba80ff6a846024153b8e31e60fcecfd3b8473ff12172bb58801cea842c921f
7
+ data.tar.gz: 1901f329e2f9c3023e25a2bd198c0a5aa89efbbf40e33dbd25e31d56c5584bcd30472878fb07a19fa9ca24d743c7f6c60744081c76ab4aeb0081f73efaae5207
Binary file
data.tar.gz.sig CHANGED
Binary file
@@ -1,5 +1,23 @@
1
- ### 3.8 Development
2
- [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.7.0...master)
1
+ ### 3.8.0 / 2018-08-04
2
+ [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.7.0...v3.8.0)
3
+
4
+ Enhancements:
5
+
6
+ * Improve failure message of `change(receiver, :message)` by including the
7
+ receiver as `SomeClass#some_message`. (Tomohiro Hashidate, #1005)
8
+ * Improve `change` matcher so that it can correctly detect changes in
9
+ deeply nested mutable objects (such as arrays-of-hashes-of-arrays).
10
+ The improved logic uses the before/after `hash` value to see if the
11
+ object has been mutated, rather than shallow duping the object.
12
+ (Myron Marston, #1034)
13
+ * Improve `include` matcher so that pseudo-hash objects (e.g. objects
14
+ that decorate a hash using a `SimpleDelegator` or similar) are treated
15
+ as a hash, as long as they implement `to_hash`. (Pablo Brasero, #1012)
16
+ * Add `max_formatted_output_length=` to configuration, allowing changing
17
+ the length at which we truncate large output strings.
18
+ (Sam Phippen #951, Benoit Tigeot #1056)
19
+ * Improve error message when passing a matcher that doesn't support block
20
+ expectations to a block based `expect`. (@nicktime, #1066)
3
21
 
4
22
  ### 3.7.0 / 2017-10-17
5
23
  [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.6.0...v3.7.0)
data/README.md CHANGED
@@ -20,7 +20,7 @@ RSpec repos as well. Add the following to your `Gemfile`:
20
20
 
21
21
  ```ruby
22
22
  %w[rspec-core rspec-expectations rspec-mocks rspec-support].each do |lib|
23
- gem lib, :git => "git://github.com/rspec/#{lib}.git", :branch => 'master'
23
+ gem lib, :git => "https://github.com/rspec/#{lib}.git", :branch => 'master'
24
24
  end
25
25
  ```
26
26
 
@@ -1,7 +1,7 @@
1
1
  module RSpec
2
2
  module Expectations
3
3
  # @private
4
- class BlockSnippetExtractor # rubocop:disable Style/ClassLength
4
+ class BlockSnippetExtractor # rubocop:disable Metrics/ClassLength
5
5
  # rubocop should properly handle `Struct.new {}` as an inner class definition.
6
6
 
7
7
  attr_reader :proc, :method_name
@@ -56,6 +56,20 @@ module RSpec
56
56
  end
57
57
  end
58
58
 
59
+ # Configures the maximum character length that RSpec will print while
60
+ # formatting an object. You can set length to nil to prevent RSpec from
61
+ # doing truncation.
62
+ # @param [Fixnum] length the number of characters to limit the formatted output to.
63
+ # @example
64
+ # RSpec.configure do |rspec|
65
+ # rspec.expect_with :rspec do |c|
66
+ # c.max_formatted_output_length = 200
67
+ # end
68
+ # end
69
+ def max_formatted_output_length=(length)
70
+ RSpec::Support::ObjectFormatter.default_instance.max_formatted_output_length = length
71
+ end
72
+
59
73
  # The list of configured syntaxes.
60
74
  # @return [Array<Symbol>] the list of configured syntaxes.
61
75
  # @example
@@ -112,7 +112,7 @@ module RSpec
112
112
  def enforce_block_expectation(matcher)
113
113
  return if supports_block_expectations?(matcher)
114
114
 
115
- raise ExpectationNotMetError, "You must pass an argument rather than a block to use the provided " \
115
+ raise ExpectationNotMetError, "You must pass an argument rather than a block to `expect` to use the provided " \
116
116
  "matcher (#{RSpec::Support::ObjectFormatter.format(matcher)}), or the matcher must implement " \
117
117
  "`supports_block_expectations?`."
118
118
  end
@@ -53,6 +53,6 @@ module RSpec
53
53
  module Expectations
54
54
  remove_const :ExpectationNotMetError
55
55
  # Exception raised when an expectation fails.
56
- ExpectationNotMetError = ::Minitest::Assertion
56
+ const_set :ExpectationNotMetError, ::Minitest::Assertion
57
57
  end
58
58
  end
@@ -106,7 +106,7 @@ if defined?(BasicObject)
106
106
  # that this syntax does not always play nice with delegate/proxy objects.
107
107
  # We recommend you use the non-monkeypatching `:expect` syntax instead.
108
108
  class BasicObject
109
- # @method should
109
+ # @method should(matcher, message)
110
110
  # Passes if `matcher` returns true. Available on every `Object`.
111
111
  # @example
112
112
  # actual.should eq expected
@@ -118,7 +118,7 @@ if defined?(BasicObject)
118
118
  # @note This is only available when you have enabled the `:should` syntax.
119
119
  # @see RSpec::Matchers
120
120
 
121
- # @method should_not
121
+ # @method should_not(matcher, message)
122
122
  # Passes if `matcher` returns false. Available on every `Object`.
123
123
  # @example
124
124
  # actual.should_not eq expected
@@ -2,7 +2,7 @@ module RSpec
2
2
  module Expectations
3
3
  # @private
4
4
  module Version
5
- STRING = '3.7.0'
5
+ STRING = '3.8.0'
6
6
  end
7
7
  end
8
8
  end
@@ -480,7 +480,10 @@ module RSpec
480
480
  # == Notes
481
481
  #
482
482
  # Evaluates `receiver.message` or `block` before and after it
483
- # evaluates the block passed to `expect`.
483
+ # evaluates the block passed to `expect`. If the value is the same
484
+ # object, its before/after `hash` value is used to see if it has changed.
485
+ # Therefore, your object needs to properly implement `hash` to work correctly
486
+ # with this matcher.
484
487
  #
485
488
  # `expect( ... ).not_to change` supports the form that specifies `from`
486
489
  # (which specifies what you expect the starting, unchanged value to be)
@@ -43,16 +43,13 @@ module RSpec
43
43
 
44
44
  # @private
45
45
  def matches?(event_proc)
46
- @event_proc = event_proc
47
- return false unless Proc === event_proc
48
46
  raise_block_syntax_error if block_given?
49
- change_details.perform_change(event_proc)
50
- change_details.changed?
47
+ perform_change(event_proc) && change_details.changed?
51
48
  end
52
49
 
53
50
  def does_not_match?(event_proc)
54
51
  raise_block_syntax_error if block_given?
55
- !matches?(event_proc) && Proc === event_proc
52
+ perform_change(event_proc) && !change_details.changed?
56
53
  end
57
54
 
58
55
  # @api private
@@ -92,6 +89,18 @@ module RSpec
92
89
  @change_details ||= ChangeDetails.new(matcher_name, @receiver, @message, &@block)
93
90
  end
94
91
 
92
+ def perform_change(event_proc)
93
+ @event_proc = event_proc
94
+ change_details.perform_change(event_proc) do |actual_before|
95
+ # pre-compute values derived from the `before` value before the
96
+ # mutation is applied, in case the specified mutation is mutation
97
+ # of a single object (rather than a changing what object a method
98
+ # returns). We need to cache these values before the `before` value
99
+ # they are based on potentially gets mutated.
100
+ @actual_before_description = description_of(actual_before)
101
+ end
102
+ end
103
+
95
104
  def raise_block_syntax_error
96
105
  raise SyntaxError, "Block not received by the `change` matcher. " \
97
106
  "Perhaps you want to use `{ ... }` instead of do/end?"
@@ -99,12 +108,12 @@ module RSpec
99
108
 
100
109
  def positive_failure_reason
101
110
  return "was not given a block" unless Proc === @event_proc
102
- "is still #{description_of change_details.actual_before}"
111
+ "is still #{@actual_before_description}"
103
112
  end
104
113
 
105
114
  def negative_failure_reason
106
115
  return "was not given a block" unless Proc === @event_proc
107
- "did change from #{description_of change_details.actual_before} " \
116
+ "did change from #{@actual_before_description} " \
108
117
  "to #{description_of change_details.actual_after}"
109
118
  end
110
119
  end
@@ -129,9 +138,7 @@ module RSpec
129
138
  # @private
130
139
  def matches?(event_proc)
131
140
  @event_proc = event_proc
132
- return false unless Proc === event_proc
133
- @change_details.perform_change(event_proc)
134
- @comparer.call(@change_details.actual_delta)
141
+ @change_details.perform_change(event_proc) && @comparer.call(@change_details.actual_delta)
135
142
  end
136
143
 
137
144
  # @private
@@ -173,10 +180,7 @@ module RSpec
173
180
 
174
181
  # @private
175
182
  def matches?(event_proc)
176
- @event_proc = event_proc
177
- return false unless Proc === event_proc
178
- @change_details.perform_change(event_proc)
179
- @change_details.changed? && matches_before? && matches_after?
183
+ perform_change(event_proc) && @change_details.changed? && @matches_before && matches_after?
180
184
  end
181
185
 
182
186
  # @private
@@ -187,7 +191,7 @@ module RSpec
187
191
  # @private
188
192
  def failure_message
189
193
  return not_given_a_block_failure unless Proc === @event_proc
190
- return before_value_failure unless matches_before?
194
+ return before_value_failure unless @matches_before
191
195
  return did_not_change_failure unless @change_details.changed?
192
196
  after_value_failure
193
197
  end
@@ -199,8 +203,17 @@ module RSpec
199
203
 
200
204
  private
201
205
 
202
- def matches_before?
203
- values_match?(@expected_before, @change_details.actual_before)
206
+ def perform_change(event_proc)
207
+ @event_proc = event_proc
208
+ @change_details.perform_change(event_proc) do |actual_before|
209
+ # pre-compute values derived from the `before` value before the
210
+ # mutation is applied, in case the specified mutation is mutation
211
+ # of a single object (rather than a changing what object a method
212
+ # returns). We need to cache these values before the `before` value
213
+ # they are based on potentially gets mutated.
214
+ @matches_before = values_match?(@expected_before, actual_before)
215
+ @actual_before_description = description_of(actual_before)
216
+ end
204
217
  end
205
218
 
206
219
  def matches_after?
@@ -210,7 +223,7 @@ module RSpec
210
223
  def before_value_failure
211
224
  "expected #{@change_details.value_representation} " \
212
225
  "to have initially been #{description_of @expected_before}, " \
213
- "but was #{description_of @change_details.actual_before}"
226
+ "but was #{@actual_before_description}"
214
227
  end
215
228
 
216
229
  def after_value_failure
@@ -226,7 +239,7 @@ module RSpec
226
239
 
227
240
  def did_change_failure
228
241
  "expected #{@change_details.value_representation} not to have changed, but " \
229
- "did change from #{description_of @change_details.actual_before} " \
242
+ "did change from #{@actual_before_description} " \
230
243
  "to #{description_of @change_details.actual_after}"
231
244
  end
232
245
 
@@ -260,16 +273,13 @@ module RSpec
260
273
  "is not supported"
261
274
  end
262
275
 
263
- @event_proc = event_proc
264
- return false unless Proc === event_proc
265
- @change_details.perform_change(event_proc)
266
- !@change_details.changed? && matches_before?
276
+ perform_change(event_proc) && !@change_details.changed? && @matches_before
267
277
  end
268
278
 
269
279
  # @private
270
280
  def failure_message_when_negated
271
281
  return not_given_a_block_failure unless Proc === @event_proc
272
- return before_value_failure unless matches_before?
282
+ return before_value_failure unless @matches_before
273
283
  did_change_failure
274
284
  end
275
285
 
@@ -312,8 +322,20 @@ module RSpec
312
322
 
313
323
  # @private
314
324
  # Encapsulates the details of the before/after values.
325
+ #
326
+ # Note that this class exposes the `actual_after` value, to allow the
327
+ # matchers above to derive failure messages, etc from the value on demand
328
+ # as needed, but it intentionally does _not_ expose the `actual_before`
329
+ # value. Some usages of the `change` matcher mutate a specific object
330
+ # returned by the value proc, which means that failure message snippets,
331
+ # etc, which are derived from the `before` value may not be accurate if
332
+ # they are lazily computed as needed. We must pre-compute them before
333
+ # applying the change in the `expect` block. To ensure that all `change`
334
+ # matchers do that properly, we do not expose the `actual_before` value.
335
+ # Instead, matchers must pass a block to `perform_change`, which yields
336
+ # the `actual_before` value before applying the change.
315
337
  class ChangeDetails
316
- attr_reader :actual_before, :actual_after
338
+ attr_reader :actual_after
317
339
 
318
340
  def initialize(matcher_name, receiver=nil, message=nil, &block)
319
341
  if receiver && !message
@@ -334,7 +356,7 @@ module RSpec
334
356
  def value_representation
335
357
  @value_representation ||=
336
358
  if @message
337
- "##{@message}"
359
+ "`#{message_notation(@receiver, @message)}`"
338
360
  elsif (value_block_snippet = extract_value_block_snippet)
339
361
  "`#{value_block_snippet}`"
340
362
  else
@@ -344,12 +366,29 @@ module RSpec
344
366
 
345
367
  def perform_change(event_proc)
346
368
  @actual_before = evaluate_value_proc
369
+ @before_hash = @actual_before.hash
370
+ yield @actual_before if block_given?
371
+
372
+ return false unless Proc === event_proc
347
373
  event_proc.call
374
+
348
375
  @actual_after = evaluate_value_proc
376
+ true
349
377
  end
350
378
 
351
379
  def changed?
352
- @actual_before != @actual_after
380
+ # Consider it changed if either:
381
+ #
382
+ # - The before/after values are unequal
383
+ # - The before/after values have different hash values
384
+ #
385
+ # The latter case specifically handles the case when the value proc
386
+ # returns the exact same object, but it has been mutated.
387
+ #
388
+ # Note that it is not sufficient to only check the hashes; it is
389
+ # possible for two values to be unequal (and of different classes)
390
+ # but to return the same hash value.
391
+ @actual_before != @actual_after || @before_hash != @actual_after.hash
353
392
  end
354
393
 
355
394
  def actual_delta
@@ -359,15 +398,15 @@ module RSpec
359
398
  private
360
399
 
361
400
  def evaluate_value_proc
362
- value_proc = @value_proc || lambda { @receiver.__send__(@message) }
401
+ @value_proc ? @value_proc.call : @receiver.__send__(@message)
402
+ end
363
403
 
364
- case val = value_proc.call
365
- when IO # enumerable, but we don't want to dup it.
366
- val
367
- when Enumerable, String
368
- val.dup
404
+ def message_notation(receiver, message)
405
+ case receiver
406
+ when Module
407
+ "#{receiver}.#{message}"
369
408
  else
370
- val
409
+ "#{Support.class_of(receiver)}##{message}"
371
410
  end
372
411
  end
373
412
 
@@ -3,7 +3,6 @@ module RSpec
3
3
  module BuiltIn
4
4
  # @api private
5
5
  # Base class for `and` and `or` compound matchers.
6
- # rubocop:disable ClassLength
7
6
  class Compound < BaseMatcher
8
7
  # @private
9
8
  attr_reader :matcher_1, :matcher_2, :evaluator
@@ -89,7 +89,7 @@ module RSpec
89
89
  elsif actual.respond_to?(:to_a) && !to_a_disallowed?(actual)
90
90
  @actual = actual.to_a
91
91
  else
92
- return false
92
+ false
93
93
  end
94
94
  end
95
95
 
@@ -176,6 +176,7 @@ module RSpec
176
176
  #
177
177
  # @private
178
178
  class PairingsMaximizer
179
+ # @private
179
180
  Solution = Struct.new(:unmatched_expected_indexes, :unmatched_actual_indexes,
180
181
  :indeterminate_expected_indexes, :indeterminate_actual_indexes) do
181
182
  def worse_than?(other)
@@ -77,7 +77,7 @@ module RSpec
77
77
  end
78
78
 
79
79
  def method_description
80
- @method_name.to_s.gsub('_', ' ')
80
+ @method_name.to_s.tr('_', ' ')
81
81
  end
82
82
 
83
83
  def args_description
@@ -15,12 +15,14 @@ module RSpec
15
15
  # @api private
16
16
  # @return [Boolean]
17
17
  def matches?(actual)
18
+ actual = actual.to_hash if actual.respond_to?(:to_hash)
18
19
  perform_match(actual) { |v| v }
19
20
  end
20
21
 
21
22
  # @api private
22
23
  # @return [Boolean]
23
24
  def does_not_match?(actual)
25
+ actual = actual.to_hash if actual.respond_to?(:to_hash)
24
26
  perform_match(actual) { |v| !v }
25
27
  end
26
28
 
@@ -151,7 +151,7 @@ module RSpec
151
151
  @expected_keywords.map(&:inspect).join(' and ')
152
152
  else
153
153
  "#{@expected_keywords[0...-1].map(&:inspect).join(', ')}, and #{@expected_keywords.last.inspect}"
154
- end
154
+ end
155
155
 
156
156
  "keyword#{@expected_keywords.count == 1 ? '' : 's'} #{kw_str}"
157
157
  end
@@ -34,7 +34,7 @@ module RSpec
34
34
  "expected #{actual_formatted} not to #{description}"
35
35
  end
36
36
 
37
- private # rubocop:disable Lint/UselessAccessModifier
37
+ private
38
38
 
39
39
  if RSpec::Support::RubyFeatures.ripper_supported?
40
40
  def block_representation
@@ -156,10 +156,12 @@ module RSpec
156
156
  # Wraps an item in order to surface its `description` via `inspect`.
157
157
  # @api private
158
158
  DescribableItem = Struct.new(:item) do
159
+ # Inspectable version of the item description
159
160
  def inspect
160
161
  "(#{item.description})"
161
162
  end
162
163
 
164
+ # A pretty printed version of the item description.
163
165
  def pretty_print(pp)
164
166
  pp.text "(#{item.description})"
165
167
  end
@@ -44,14 +44,14 @@ module RSpec
44
44
  # So it appears that `Array` can trigger that (e.g. by calling `to_a` on the passed object?)
45
45
  # So here we replace `Kernel#Array` with our own warning-free implementation for 1.8.7.
46
46
  # @private
47
- # rubocop:disable Style/MethodName
47
+ # rubocop:disable Naming/MethodName
48
48
  def self.Array(obj)
49
49
  case obj
50
50
  when Array then obj
51
51
  else [obj]
52
52
  end
53
53
  end
54
- # rubocop:enable Style/MethodName
54
+ # rubocop:enable Naming/MethodName
55
55
  end
56
56
  end
57
57
  end
@@ -21,8 +21,7 @@ module RSpec
21
21
  "#{last_expectation_handler.verb} #{last_description}"
22
22
  end
23
23
 
24
- private
25
-
24
+ # @private
26
25
  def self.last_description
27
26
  last_matcher.respond_to?(:description) ? last_matcher.description : <<-MESSAGE
28
27
  When you call a matcher in an example without a String, like this:
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.7.0
4
+ version: 3.8.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: 2017-10-17 00:00:00.000000000 Z
48
+ date: 2018-08-04 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.7.0
56
+ version: 3.8.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.7.0
63
+ version: 3.8.0
64
64
  - !ruby/object:Gem::Dependency
65
65
  name: diff-lcs
66
66
  requirement: !ruby/object:Gem::Requirement
@@ -218,9 +218,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
218
218
  version: '0'
219
219
  requirements: []
220
220
  rubyforge_project:
221
- rubygems_version: 2.6.14
221
+ rubygems_version: 2.6.13
222
222
  signing_key:
223
223
  specification_version: 4
224
- summary: rspec-expectations-3.7.0
224
+ summary: rspec-expectations-3.8.0
225
225
  test_files: []
226
- has_rdoc:
metadata.gz.sig CHANGED
@@ -1,5 +1,3 @@
1
- ��+#i*R�S��
2
- p^6w��l&�?�G&���h�ϏOe�$�Hc�x��rv'D�*Ib��[(�^+k�}CJs�� NB��+ G�)��!(&�B�
3
- f�}�:�Yf��Y��k�\��y=>���Rx��w��'n'B0\���M|s9�#m�\pF��{ţ��I��MmOf��n�&ȵWGh��O
4
- /�$!>���878�8�f6���bDGȝI�9�����vZ�_ t��,(��t$�N�ޔ�.�?�24�5�FD�ǔV�O&��E��^��F�]��V(��W}�y�d(CUw�����Rr8qƤ0�vǣ2髜�:V���-p6q �h��P#� �7�[�5�W͓-�yIl�ػ���'cS<Av��By;���(1��a�I�䝰εY�*����X�R}�v5ڵ�p��o3Q�u����8%:>U���Q��QLܡ���%i��D������nK���o�����@��O_@�k7x}
5
- =
1
+ �q�/F
2
+ Q3m_᳼��m0yvy %g��yW��_Nk�—e38r/��#�
3
+ V�����_�ێ�8����DX[��zwm �&Zg%���?�`=�5������V�h�m�R+,6�H��~c�0I�d�1v�G��h�H����\��}����hr*�N�o֓C����^�OW]v�};W�-�}>�_Gy1��<X������1j q�;�(��Z{�ܦ��d^z��\��/q[�� P��,�܅7�G