rspec-expectations 3.2.1 → 3.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/Changelog.md +55 -4
  5. data/README.md +1 -1
  6. data/lib/rspec/expectations.rb +13 -1
  7. data/lib/rspec/expectations/configuration.rb +17 -0
  8. data/lib/rspec/expectations/expectation_target.rb +3 -9
  9. data/lib/rspec/expectations/fail_with.rb +1 -3
  10. data/lib/rspec/expectations/failure_aggregator.rb +194 -0
  11. data/lib/rspec/expectations/minitest_integration.rb +13 -0
  12. data/lib/rspec/expectations/version.rb +1 -1
  13. data/lib/rspec/matchers.rb +59 -5
  14. data/lib/rspec/matchers/built_in/base_matcher.rb +56 -7
  15. data/lib/rspec/matchers/built_in/be.rb +25 -15
  16. data/lib/rspec/matchers/built_in/be_between.rb +1 -1
  17. data/lib/rspec/matchers/built_in/be_within.rb +2 -2
  18. data/lib/rspec/matchers/built_in/contain_exactly.rb +12 -8
  19. data/lib/rspec/matchers/built_in/eq.rb +3 -38
  20. data/lib/rspec/matchers/built_in/eql.rb +2 -2
  21. data/lib/rspec/matchers/built_in/equal.rb +3 -3
  22. data/lib/rspec/matchers/built_in/exist.rb +2 -2
  23. data/lib/rspec/matchers/built_in/has.rb +3 -1
  24. data/lib/rspec/matchers/built_in/have_attributes.rb +5 -4
  25. data/lib/rspec/matchers/built_in/include.rb +44 -19
  26. data/lib/rspec/matchers/built_in/match.rb +9 -1
  27. data/lib/rspec/matchers/built_in/operators.rb +14 -5
  28. data/lib/rspec/matchers/built_in/output.rb +9 -2
  29. data/lib/rspec/matchers/built_in/raise_error.rb +64 -22
  30. data/lib/rspec/matchers/built_in/respond_to.rb +2 -3
  31. data/lib/rspec/matchers/built_in/satisfy.rb +7 -9
  32. data/lib/rspec/matchers/built_in/start_or_end_with.rb +3 -1
  33. data/lib/rspec/matchers/built_in/throw_symbol.rb +1 -1
  34. data/lib/rspec/matchers/built_in/yield.rb +7 -5
  35. data/lib/rspec/matchers/composable.rb +5 -4
  36. data/lib/rspec/matchers/dsl.rb +19 -6
  37. data/lib/rspec/matchers/english_phrasing.rb +42 -0
  38. data/lib/rspec/matchers/expecteds_for_multiple_diffs.rb +2 -8
  39. data/lib/rspec/matchers/fail_matchers.rb +42 -0
  40. data/lib/rspec/matchers/matcher_delegator.rb +2 -0
  41. metadata +9 -7
  42. metadata.gz.sig +0 -0
  43. data/lib/rspec/matchers/pretty.rb +0 -77
@@ -114,7 +114,7 @@ module RSpec
114
114
  end
115
115
 
116
116
  def throw_description(symbol, arg)
117
- symbol_description = symbol.is_a?(String) ? symbol : symbol.inspect
117
+ symbol_description = symbol.is_a?(String) ? symbol : description_of(symbol)
118
118
 
119
119
  arg_description = if arg
120
120
  " with #{description_of arg}"
@@ -78,6 +78,7 @@ module RSpec
78
78
  "matcher. Pass the argument as a block on to the method you are testing."
79
79
  end
80
80
  else
81
+ # :nocov:
81
82
  # On 1.8.7, `lambda { }.arity` and `lambda { |*a| }.arity` both return -1,
82
83
  # so we can't distinguish between accepting no args and an arg splat.
83
84
  # It's OK to skip, this, though; it just provides a nice error message
@@ -86,6 +87,7 @@ module RSpec
86
87
  def assert_valid_expect_block!
87
88
  # nothing to do
88
89
  end
90
+ # :nocov:
89
91
  end
90
92
  end
91
93
 
@@ -247,7 +249,7 @@ module RSpec
247
249
  def positive_failure_reason
248
250
  return "was not a block" unless @probe.has_block?
249
251
  return "did not yield" if @probe.num_yields.zero?
250
- "yielded with arguments: #{@probe.single_yield_args.inspect}"
252
+ "yielded with arguments: #{description_of @probe.single_yield_args}"
251
253
  end
252
254
 
253
255
  def negative_failure_reason
@@ -317,7 +319,7 @@ module RSpec
317
319
  elsif all_args_match?
318
320
  "yielded with expected arguments" \
319
321
  "\nexpected not: #{surface_descriptions_in(@expected).inspect}" +
320
- "\n got: #{@actual.inspect}"
322
+ "\n got: #{actual_formatted}"
321
323
  else
322
324
  "did"
323
325
  end
@@ -332,7 +334,7 @@ module RSpec
332
334
  unless (match = all_args_match?)
333
335
  @positive_args_failure = "yielded with unexpected arguments" \
334
336
  "\nexpected: #{surface_descriptions_in(@expected).inspect}" +
335
- "\n got: #{@actual.inspect}"
337
+ "\n got: #{actual_formatted}"
336
338
  end
337
339
 
338
340
  match
@@ -400,7 +402,7 @@ module RSpec
400
402
 
401
403
  "yielded with unexpected arguments" \
402
404
  "\nexpected: #{surface_descriptions_in(@expected).inspect}" \
403
- "\n got: #{@actual.inspect}"
405
+ "\n got: #{actual_formatted}"
404
406
  end
405
407
 
406
408
  def negative_failure_reason
@@ -408,7 +410,7 @@ module RSpec
408
410
 
409
411
  "yielded with expected arguments" \
410
412
  "\nexpected not: #{surface_descriptions_in(@expected).inspect}" \
411
- "\n got: #{@actual.inspect}"
413
+ "\n got: #{actual_formatted}"
412
414
  end
413
415
  end
414
416
  end
@@ -80,8 +80,7 @@ module RSpec
80
80
  #
81
81
  # @!visibility public
82
82
  def description_of(object)
83
- return object.description if Matchers.is_a_describable_matcher?(object)
84
- object.inspect
83
+ RSpec::Support::ObjectFormatter.format(object)
85
84
  end
86
85
 
87
86
  # Transforms the given data structue (typically a hash or array)
@@ -102,12 +101,12 @@ module RSpec
102
101
  elsif Hash === item
103
102
  Hash[surface_descriptions_in(item.to_a)]
104
103
  elsif Struct === item
105
- item.inspect
104
+ RSpec::Support::ObjectFormatter.format(item)
106
105
  elsif should_enumerate?(item)
107
106
  begin
108
107
  item.map { |subitem| surface_descriptions_in(subitem) }
109
108
  rescue IOError # STDOUT is enumerable but `map` raises an error
110
- item.inspect
109
+ RSpec::Support::ObjectFormatter.format(item)
111
110
  end
112
111
  else
113
112
  item
@@ -149,6 +148,7 @@ module RSpec
149
148
  end
150
149
 
151
150
  if String.ancestors.include?(Enumerable) # 1.8.7
151
+ # :nocov:
152
152
  # Strings are not enumerable on 1.9, and on 1.8 they are an infinitely
153
153
  # nested enumerable: since ruby lacks a character class, it yields
154
154
  # 1-character strings, which are themselves enumerable, composed of a
@@ -159,6 +159,7 @@ module RSpec
159
159
  return false if String === item
160
160
  Enumerable === item && !(Range === item)
161
161
  end
162
+ # :nocov:
162
163
  else
163
164
  # @api private
164
165
  def should_enumerate?(item)
@@ -24,9 +24,11 @@ module RSpec
24
24
  end
25
25
  end
26
26
  else
27
+ # :nocov:
27
28
  def warn_about_block_args(*)
28
29
  # There's no way to detect block params on 1.8 since the method reflection APIs don't expose it
29
30
  end
31
+ # :nocov:
30
32
  end
31
33
 
32
34
  RSpec.configure { |c| c.extend self } if RSpec.respond_to?(:configure)
@@ -58,13 +60,18 @@ module RSpec
58
60
  define_user_override(:matches?, match_block) do |actual|
59
61
  begin
60
62
  @actual = actual
61
- super(*actual_arg_for(match_block))
63
+ RSpec::Support.with_failure_notifier(RAISE_NOTIFIER) do
64
+ super(*actual_arg_for(match_block))
65
+ end
62
66
  rescue RSpec::Expectations::ExpectationNotMetError
63
67
  false
64
68
  end
65
69
  end
66
70
  end
67
71
 
72
+ # @private
73
+ RAISE_NOTIFIER = Proc.new { |err, _opts| raise err }
74
+
68
75
  # Use this to define the block for a negative expectation (`expect(...).not_to`)
69
76
  # when the positive and negative forms require different handling. This
70
77
  # is rarely necessary, but can be helpful, for example, when specifying
@@ -300,7 +307,9 @@ module RSpec
300
307
 
301
308
  # The default description.
302
309
  def description
303
- "#{name_to_sentence}#{to_sentence expected}#{chained_method_clause_sentences}"
310
+ english_name = EnglishPhrasing.split_words(name)
311
+ expected_list = EnglishPhrasing.list(expected)
312
+ "#{english_name}#{expected_list}#{chained_method_clause_sentences}"
304
313
  end
305
314
 
306
315
  # Matchers do not support block expectations by default. You
@@ -320,7 +329,9 @@ module RSpec
320
329
  return '' unless Expectations.configuration.include_chain_clauses_in_custom_matcher_descriptions?
321
330
 
322
331
  @chained_method_clauses.map do |(method_name, method_args)|
323
- " #{split_words(method_name)}#{to_sentence(method_args)}"
332
+ english_name = EnglishPhrasing.split_words(method_name)
333
+ arg_list = EnglishPhrasing.list(method_args)
334
+ " #{english_name}#{arg_list}"
324
335
  end.join
325
336
  end
326
337
  end
@@ -336,9 +347,6 @@ module RSpec
336
347
  # Allows expectation expressions to be used in the match block.
337
348
  include RSpec::Matchers
338
349
 
339
- # Converts matcher name and expected args to an English expresion.
340
- include RSpec::Matchers::Pretty
341
-
342
350
  # Supports the matcher composability features of RSpec 3+.
343
351
  include Composable
344
352
 
@@ -357,6 +365,9 @@ module RSpec
357
365
  # The block parameter used in the expectation
358
366
  attr_reader :block_arg
359
367
 
368
+ # The name of the matcher.
369
+ attr_reader :name
370
+
360
371
  # @api private
361
372
  def initialize(name, declarations, matcher_execution_context, *expected, &block_arg)
362
373
  @name = name
@@ -406,11 +417,13 @@ module RSpec
406
417
  super || @matcher_execution_context.respond_to?(method, include_private)
407
418
  end
408
419
  else # for 1.8.7
420
+ # :nocov:
409
421
  # Indicates that this matcher responds to messages
410
422
  # from the `@matcher_execution_context` as well.
411
423
  def respond_to?(method, include_private=false)
412
424
  super || @matcher_execution_context.respond_to?(method, include_private)
413
425
  end
426
+ # :nocov:
414
427
  end
415
428
 
416
429
  private
@@ -0,0 +1,42 @@
1
+ module RSpec
2
+ module Matchers
3
+ # Facilitates converting ruby objects to English phrases.
4
+ module EnglishPhrasing
5
+ # Converts a symbol into an English expression.
6
+ #
7
+ # split_words(:banana_creme_pie) #=> "banana creme pie"
8
+ #
9
+ def self.split_words(sym)
10
+ sym.to_s.gsub(/_/, ' ')
11
+ end
12
+
13
+ # @note The returned string has a leading space except
14
+ # when given an empty list.
15
+ #
16
+ # Converts an object (often a collection of objects)
17
+ # into an English list.
18
+ #
19
+ # list(['banana', 'kiwi', 'mango'])
20
+ # #=> " \"banana\", \"kiwi\", and \"mango\""
21
+ #
22
+ # Given an empty collection, returns the empty string.
23
+ #
24
+ # list([]) #=> ""
25
+ #
26
+ def self.list(obj)
27
+ return " #{RSpec::Support::ObjectFormatter.format(obj)}" if !obj || Struct === obj
28
+ items = Array(obj).map { |w| RSpec::Support::ObjectFormatter.format(w) }
29
+ case items.length
30
+ when 0
31
+ ""
32
+ when 1
33
+ " #{items[0]}"
34
+ when 2
35
+ " #{items[0]} and #{items[1]}"
36
+ else
37
+ " #{items[0...-1].join(', ')}, and #{items[-1]}"
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -53,13 +53,7 @@ module RSpec
53
53
  private
54
54
 
55
55
  def self.diff_label_for(matcher)
56
- "Diff for (#{truncated(description_for(matcher))}):"
57
- end
58
-
59
- def self.description_for(matcher)
60
- matcher.description
61
- rescue NoMethodError
62
- matcher.inspect
56
+ "Diff for (#{truncated(RSpec::Support::ObjectFormatter.format(matcher))}):"
63
57
  end
64
58
 
65
59
  def self.truncated(description)
@@ -70,7 +64,7 @@ module RSpec
70
64
  def diffs(differ, actual)
71
65
  @expected_list.map do |(expected, diff_label)|
72
66
  diff = differ.diff(actual, expected)
73
- next if diff.empty?
67
+ next if diff.strip.empty?
74
68
  "#{diff_label}#{diff}"
75
69
  end.compact.join("\n")
76
70
  end
@@ -0,0 +1,42 @@
1
+ require 'rspec/expectations'
2
+
3
+ module RSpec
4
+ module Matchers
5
+ # Matchers for testing RSpec matchers. Include them with:
6
+ #
7
+ # require 'rspec/matchers/fail_matchers'
8
+ # RSpec.configure do |config|
9
+ # config.include RSpec::Matchers::FailMatchers
10
+ # end
11
+ #
12
+ module FailMatchers
13
+ # Matches if an expectation fails
14
+ #
15
+ # @example
16
+ # expect { some_expectation }.to fail
17
+ def fail(&block)
18
+ raise_error(RSpec::Expectations::ExpectationNotMetError, &block)
19
+ end
20
+
21
+ # Matches if an expectation fails with the provided message
22
+ #
23
+ # @example
24
+ # expect { some_expectation }.to fail_with("some failure message")
25
+ # expect { some_expectation }.to fail_with(/some failure message/)
26
+ def fail_with(message)
27
+ raise_error(RSpec::Expectations::ExpectationNotMetError, message)
28
+ end
29
+
30
+ # Matches if an expectation fails including the provided message
31
+ #
32
+ # @example
33
+ # expect { some_expectation }.to fail_including("portion of some failure message")
34
+ def fail_including(*snippets)
35
+ raise_error(
36
+ RSpec::Expectations::ExpectationNotMetError,
37
+ a_string_including(*snippets)
38
+ )
39
+ end
40
+ end
41
+ end
42
+ end
@@ -19,9 +19,11 @@ module RSpec
19
19
  super || base_matcher.respond_to?(name, include_all)
20
20
  end
21
21
  else
22
+ # :nocov:
22
23
  def respond_to?(name, include_all=false)
23
24
  super || base_matcher.respond_to?(name, include_all)
24
25
  end
26
+ # :nocov:
25
27
  end
26
28
 
27
29
  def initialize_copy(other)
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.2.1
4
+ version: 3.3.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-04-06 00:00:00.000000000 Z
48
+ date: 2015-06-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.2.0
56
+ version: 3.3.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.2.0
63
+ version: 3.3.0
64
64
  - !ruby/object:Gem::Dependency
65
65
  name: diff-lcs
66
66
  requirement: !ruby/object:Gem::Requirement
@@ -153,6 +153,7 @@ files:
153
153
  - lib/rspec/expectations/configuration.rb
154
154
  - lib/rspec/expectations/expectation_target.rb
155
155
  - lib/rspec/expectations/fail_with.rb
156
+ - lib/rspec/expectations/failure_aggregator.rb
156
157
  - lib/rspec/expectations/handler.rb
157
158
  - lib/rspec/expectations/minitest_integration.rb
158
159
  - lib/rspec/expectations/syntax.rb
@@ -189,11 +190,12 @@ files:
189
190
  - lib/rspec/matchers/built_in/yield.rb
190
191
  - lib/rspec/matchers/composable.rb
191
192
  - lib/rspec/matchers/dsl.rb
193
+ - lib/rspec/matchers/english_phrasing.rb
192
194
  - lib/rspec/matchers/expecteds_for_multiple_diffs.rb
195
+ - lib/rspec/matchers/fail_matchers.rb
193
196
  - lib/rspec/matchers/generated_descriptions.rb
194
197
  - lib/rspec/matchers/matcher_delegator.rb
195
198
  - lib/rspec/matchers/matcher_protocol.rb
196
- - lib/rspec/matchers/pretty.rb
197
199
  homepage: http://github.com/rspec/rspec-expectations
198
200
  licenses:
199
201
  - MIT
@@ -214,10 +216,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
214
216
  - !ruby/object:Gem::Version
215
217
  version: '0'
216
218
  requirements: []
217
- rubyforge_project: rspec
219
+ rubyforge_project:
218
220
  rubygems_version: 2.2.2
219
221
  signing_key:
220
222
  specification_version: 4
221
- summary: rspec-expectations-3.2.1
223
+ summary: rspec-expectations-3.3.0
222
224
  test_files: []
223
225
  has_rdoc:
metadata.gz.sig CHANGED
Binary file
@@ -1,77 +0,0 @@
1
- module RSpec
2
- module Matchers
3
- # @api private
4
- # Contains logic to facilitate converting ruby symbols and
5
- # objects to english phrases.
6
- module Pretty
7
- # @api private
8
- # Converts a symbol into an english expression.
9
- def split_words(sym)
10
- sym.to_s.gsub(/_/, ' ')
11
- end
12
- module_function :split_words
13
-
14
- # @api private
15
- # Converts a collection of objects into an english expression.
16
- def to_sentence(words)
17
- return " #{words.inspect}" if !words || Struct === words
18
- words = Array(words).map { |w| to_word(w) }
19
- case words.length
20
- when 0
21
- ""
22
- when 1
23
- " #{words[0]}"
24
- when 2
25
- " #{words[0]} and #{words[1]}"
26
- else
27
- " #{words[0...-1].join(', ')}, and #{words[-1]}"
28
- end
29
- end
30
-
31
- # @api private
32
- # Converts the given item to string suitable for use in a list expression.
33
- def to_word(item)
34
- is_matcher_with_description?(item) ? item.description : item.inspect
35
- end
36
-
37
- # @private
38
- # Provides an English expression for the matcher name.
39
- def name_to_sentence
40
- split_words(name)
41
- end
42
-
43
- # @api private
44
- # Provides a name for the matcher.
45
- def name
46
- defined?(@name) ? @name : underscore(self.class.name.split("::").last)
47
- end
48
-
49
- # @private
50
- # Borrowed from ActiveSupport
51
- def underscore(camel_cased_word)
52
- word = camel_cased_word.to_s.dup
53
- word.gsub!(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
54
- word.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
55
- word.tr!("-", "_")
56
- word.downcase!
57
- word
58
- end
59
-
60
- private
61
-
62
- def is_matcher_with_description?(object)
63
- RSpec::Matchers.is_a_matcher?(object) && object.respond_to?(:description)
64
- end
65
-
66
- # `{ :a => 5, :b => 2 }.inspect` produces:
67
- # {:a=>5, :b=>2}
68
- # ...but it looks much better as:
69
- # {:a => 5, :b => 2}
70
- #
71
- # This is idempotent and safe to run on a string multiple times.
72
- def improve_hash_formatting(inspect_string)
73
- inspect_string.gsub(/(\S)=>(\S)/, '\1 => \2')
74
- end
75
- end
76
- end
77
- end