rspec-expectations 3.7.0 → 3.8.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: 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