rspec-expectations 2.13.0 → 3.0.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.
Files changed (142) hide show
  1. checksums.yaml +15 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data/Changelog.md +413 -23
  4. data/License.txt +1 -0
  5. data/README.md +109 -80
  6. data/lib/rspec/{matchers → expectations}/configuration.rb +44 -14
  7. data/lib/rspec/expectations/expectation_target.rb +71 -38
  8. data/lib/rspec/expectations/fail_with.rb +12 -44
  9. data/lib/rspec/expectations/handler.rb +135 -35
  10. data/lib/rspec/expectations/minitest_integration.rb +16 -0
  11. data/lib/rspec/expectations/syntax.rb +60 -94
  12. data/lib/rspec/expectations/version.rb +1 -1
  13. data/lib/rspec/expectations.rb +46 -24
  14. data/lib/rspec/matchers/aliased_matcher.rb +41 -0
  15. data/lib/rspec/matchers/built_in/all.rb +78 -0
  16. data/lib/rspec/matchers/built_in/base_matcher.rb +63 -15
  17. data/lib/rspec/matchers/built_in/be.rb +170 -79
  18. data/lib/rspec/matchers/built_in/be_between.rb +77 -0
  19. data/lib/rspec/matchers/built_in/be_instance_of.rb +11 -3
  20. data/lib/rspec/matchers/built_in/be_kind_of.rb +5 -0
  21. data/lib/rspec/matchers/built_in/be_within.rb +40 -16
  22. data/lib/rspec/matchers/built_in/change.rb +275 -74
  23. data/lib/rspec/matchers/built_in/compound.rb +122 -0
  24. data/lib/rspec/matchers/built_in/contain_exactly.rb +256 -0
  25. data/lib/rspec/matchers/built_in/cover.rb +3 -0
  26. data/lib/rspec/matchers/built_in/eq.rb +60 -6
  27. data/lib/rspec/matchers/built_in/eql.rb +17 -5
  28. data/lib/rspec/matchers/built_in/equal.rb +55 -21
  29. data/lib/rspec/matchers/built_in/exist.rb +74 -10
  30. data/lib/rspec/matchers/built_in/has.rb +71 -15
  31. data/lib/rspec/matchers/built_in/include.rb +58 -29
  32. data/lib/rspec/matchers/built_in/match.rb +19 -1
  33. data/lib/rspec/matchers/built_in/operators.rb +119 -0
  34. data/lib/rspec/matchers/built_in/output.rb +150 -0
  35. data/lib/rspec/matchers/built_in/raise_error.rb +91 -33
  36. data/lib/rspec/matchers/built_in/respond_to.rb +42 -20
  37. data/lib/rspec/matchers/built_in/satisfy.rb +19 -3
  38. data/lib/rspec/matchers/built_in/start_and_end_with.rb +54 -18
  39. data/lib/rspec/matchers/built_in/throw_symbol.rb +38 -8
  40. data/lib/rspec/matchers/built_in/yield.rb +237 -55
  41. data/lib/rspec/matchers/built_in.rb +45 -33
  42. data/lib/rspec/matchers/composable.rb +179 -0
  43. data/lib/rspec/matchers/dsl.rb +362 -5
  44. data/lib/rspec/matchers/generated_descriptions.rb +13 -6
  45. data/lib/rspec/matchers/matcher_delegator.rb +37 -0
  46. data/lib/rspec/matchers/pretty.rb +33 -20
  47. data/lib/rspec/matchers.rb +450 -227
  48. data.tar.gz.sig +1 -0
  49. metadata +100 -215
  50. metadata.gz.sig +0 -0
  51. data/features/README.md +0 -49
  52. data/features/Upgrade.md +0 -53
  53. data/features/built_in_matchers/README.md +0 -90
  54. data/features/built_in_matchers/be.feature +0 -175
  55. data/features/built_in_matchers/be_within.feature +0 -48
  56. data/features/built_in_matchers/cover.feature +0 -47
  57. data/features/built_in_matchers/end_with.feature +0 -48
  58. data/features/built_in_matchers/equality.feature +0 -139
  59. data/features/built_in_matchers/exist.feature +0 -45
  60. data/features/built_in_matchers/expect_change.feature +0 -59
  61. data/features/built_in_matchers/expect_error.feature +0 -144
  62. data/features/built_in_matchers/have.feature +0 -109
  63. data/features/built_in_matchers/include.feature +0 -174
  64. data/features/built_in_matchers/match.feature +0 -52
  65. data/features/built_in_matchers/operators.feature +0 -227
  66. data/features/built_in_matchers/predicates.feature +0 -137
  67. data/features/built_in_matchers/respond_to.feature +0 -84
  68. data/features/built_in_matchers/satisfy.feature +0 -33
  69. data/features/built_in_matchers/start_with.feature +0 -48
  70. data/features/built_in_matchers/throw_symbol.feature +0 -91
  71. data/features/built_in_matchers/types.feature +0 -116
  72. data/features/built_in_matchers/yield.feature +0 -146
  73. data/features/custom_matchers/access_running_example.feature +0 -53
  74. data/features/custom_matchers/define_diffable_matcher.feature +0 -27
  75. data/features/custom_matchers/define_matcher.feature +0 -368
  76. data/features/custom_matchers/define_matcher_outside_rspec.feature +0 -38
  77. data/features/custom_matchers/define_matcher_with_fluent_interface.feature +0 -24
  78. data/features/customized_message.feature +0 -22
  79. data/features/diffing.feature +0 -85
  80. data/features/implicit_docstrings.feature +0 -52
  81. data/features/step_definitions/additional_cli_steps.rb +0 -22
  82. data/features/support/env.rb +0 -5
  83. data/features/syntax_configuration.feature +0 -68
  84. data/features/test_frameworks/test_unit.feature +0 -46
  85. data/lib/rspec/expectations/deprecation.rb +0 -38
  86. data/lib/rspec/expectations/differ.rb +0 -115
  87. data/lib/rspec/expectations/errors.rb +0 -9
  88. data/lib/rspec/expectations/extensions/array.rb +0 -9
  89. data/lib/rspec/expectations/extensions/object.rb +0 -39
  90. data/lib/rspec/expectations/extensions.rb +0 -2
  91. data/lib/rspec/matchers/be_close.rb +0 -9
  92. data/lib/rspec/matchers/built_in/have.rb +0 -108
  93. data/lib/rspec/matchers/built_in/match_array.rb +0 -51
  94. data/lib/rspec/matchers/compatibility.rb +0 -14
  95. data/lib/rspec/matchers/extensions/instance_eval_with_args.rb +0 -39
  96. data/lib/rspec/matchers/matcher.rb +0 -300
  97. data/lib/rspec/matchers/method_missing.rb +0 -12
  98. data/lib/rspec/matchers/operator_matcher.rb +0 -109
  99. data/lib/rspec-expectations.rb +0 -1
  100. data/spec/rspec/expectations/differ_spec.rb +0 -170
  101. data/spec/rspec/expectations/expectation_target_spec.rb +0 -75
  102. data/spec/rspec/expectations/extensions/kernel_spec.rb +0 -67
  103. data/spec/rspec/expectations/fail_with_spec.rb +0 -95
  104. data/spec/rspec/expectations/handler_spec.rb +0 -206
  105. data/spec/rspec/expectations/syntax_spec.rb +0 -97
  106. data/spec/rspec/matchers/base_matcher_spec.rb +0 -62
  107. data/spec/rspec/matchers/be_close_spec.rb +0 -22
  108. data/spec/rspec/matchers/be_instance_of_spec.rb +0 -63
  109. data/spec/rspec/matchers/be_kind_of_spec.rb +0 -41
  110. data/spec/rspec/matchers/be_spec.rb +0 -516
  111. data/spec/rspec/matchers/be_within_spec.rb +0 -129
  112. data/spec/rspec/matchers/change_spec.rb +0 -542
  113. data/spec/rspec/matchers/configuration_spec.rb +0 -238
  114. data/spec/rspec/matchers/cover_spec.rb +0 -69
  115. data/spec/rspec/matchers/description_generation_spec.rb +0 -176
  116. data/spec/rspec/matchers/dsl_spec.rb +0 -57
  117. data/spec/rspec/matchers/eq_spec.rb +0 -60
  118. data/spec/rspec/matchers/eql_spec.rb +0 -41
  119. data/spec/rspec/matchers/equal_spec.rb +0 -78
  120. data/spec/rspec/matchers/exist_spec.rb +0 -124
  121. data/spec/rspec/matchers/has_spec.rb +0 -122
  122. data/spec/rspec/matchers/have_spec.rb +0 -445
  123. data/spec/rspec/matchers/include_matcher_integration_spec.rb +0 -30
  124. data/spec/rspec/matchers/include_spec.rb +0 -531
  125. data/spec/rspec/matchers/match_array_spec.rb +0 -194
  126. data/spec/rspec/matchers/match_spec.rb +0 -61
  127. data/spec/rspec/matchers/matcher_spec.rb +0 -471
  128. data/spec/rspec/matchers/matchers_spec.rb +0 -37
  129. data/spec/rspec/matchers/method_missing_spec.rb +0 -28
  130. data/spec/rspec/matchers/operator_matcher_spec.rb +0 -223
  131. data/spec/rspec/matchers/raise_error_spec.rb +0 -395
  132. data/spec/rspec/matchers/respond_to_spec.rb +0 -292
  133. data/spec/rspec/matchers/satisfy_spec.rb +0 -44
  134. data/spec/rspec/matchers/start_with_end_with_spec.rb +0 -186
  135. data/spec/rspec/matchers/throw_symbol_spec.rb +0 -116
  136. data/spec/rspec/matchers/yield_spec.rb +0 -437
  137. data/spec/spec_helper.rb +0 -54
  138. data/spec/support/classes.rb +0 -56
  139. data/spec/support/in_sub_process.rb +0 -38
  140. data/spec/support/matchers.rb +0 -22
  141. data/spec/support/ruby_version.rb +0 -10
  142. data/spec/support/shared_examples.rb +0 -13
@@ -1,31 +1,36 @@
1
1
  module RSpec
2
2
  module Expectations
3
3
 
4
- class ExpectationHandler
5
- def self.message_must_be_string(msg)
6
- "WARNING: ignoring the provided expectation message argument " +
7
- "(#{msg.inspect}) since it is not a string."
8
- end
9
-
4
+ # @private
5
+ module ExpectationHelper
10
6
  def self.check_message(msg)
11
- ::Kernel.warn message_must_be_string(msg) unless msg.nil? || msg.is_a?(String)
7
+ unless msg.nil? || msg.respond_to?(:to_str) || msg.respond_to?(:call)
8
+ ::Kernel.warn [
9
+ "WARNING: ignoring the provided expectation message argument (",
10
+ msg.inspect,
11
+ ") since it is not a string or a proc."
12
+ ].join
13
+ end
12
14
  end
13
- end
14
15
 
15
- class PositiveExpectationHandler < ExpectationHandler
16
+ # Returns an RSpec-3+ compatible matcher, wrapping a legacy one
17
+ # in an adapter if necessary.
18
+ #
19
+ # @private
20
+ def self.modern_matcher_from(matcher)
21
+ LegacyMacherAdapter::RSpec2.wrap(matcher) ||
22
+ LegacyMacherAdapter::RSpec1.wrap(matcher) || matcher
23
+ end
16
24
 
17
- def self.handle_matcher(actual, matcher, message=nil, &block)
25
+ def self.setup(handler, matcher, message)
18
26
  check_message(message)
19
- ::RSpec::Matchers.last_should = :should
20
- ::RSpec::Matchers.last_matcher = matcher
21
- return ::RSpec::Matchers::BuiltIn::PositiveOperatorMatcher.new(actual) if matcher.nil?
22
-
23
- match = matcher.matches?(actual, &block)
24
- return match if match
27
+ ::RSpec::Matchers.last_expectation_handler = handler
28
+ ::RSpec::Matchers.last_matcher = modern_matcher_from(matcher)
29
+ end
25
30
 
26
- message ||= matcher.respond_to?(:failure_message_for_should) ?
27
- matcher.failure_message_for_should :
28
- matcher.failure_message
31
+ def self.handle_failure(matcher, message, failure_message_method)
32
+ message = message.call if message.respond_to?(:call)
33
+ message ||= matcher.__send__(failure_message_method)
29
34
 
30
35
  if matcher.respond_to?(:diffable?) && matcher.diffable?
31
36
  ::RSpec::Expectations.fail_with message, matcher.expected, matcher.actual
@@ -35,26 +40,121 @@ module RSpec
35
40
  end
36
41
  end
37
42
 
38
- class NegativeExpectationHandler < ExpectationHandler
39
- def self.handle_matcher(actual, matcher, message=nil, &block)
40
- check_message(message)
41
- ::RSpec::Matchers.last_should = :should_not
42
- ::RSpec::Matchers.last_matcher = matcher
43
- return ::RSpec::Matchers::BuiltIn::NegativeOperatorMatcher.new(actual) if matcher.nil?
43
+ # @private
44
+ class PositiveExpectationHandler
45
+ def self.handle_matcher(actual, initial_matcher, message=nil, &block)
46
+ matcher = ExpectationHelper.setup(self, initial_matcher, message)
44
47
 
45
- match = matcher.respond_to?(:does_not_match?) ?
46
- !matcher.does_not_match?(actual, &block) :
47
- matcher.matches?(actual, &block)
48
- return match unless match
48
+ return ::RSpec::Matchers::BuiltIn::PositiveOperatorMatcher.new(actual) unless initial_matcher
49
+ matcher.matches?(actual, &block) or ExpectationHelper.handle_failure(matcher, message, :failure_message)
50
+ end
49
51
 
50
- message ||= matcher.respond_to?(:failure_message_for_should_not) ?
51
- matcher.failure_message_for_should_not :
52
- matcher.negative_failure_message
52
+ def self.verb
53
+ "should"
54
+ end
53
55
 
54
- if matcher.respond_to?(:diffable?) && matcher.diffable?
55
- ::RSpec::Expectations.fail_with message, matcher.expected, matcher.actual
56
+ def self.should_method
57
+ :should
58
+ end
59
+
60
+ def self.opposite_should_method
61
+ :should_not
62
+ end
63
+ end
64
+
65
+ # @private
66
+ class NegativeExpectationHandler
67
+ def self.handle_matcher(actual, initial_matcher, message=nil, &block)
68
+ matcher = ExpectationHelper.setup(self, initial_matcher, message)
69
+
70
+ return ::RSpec::Matchers::BuiltIn::NegativeOperatorMatcher.new(actual) unless initial_matcher
71
+ !(does_not_match?(matcher, actual, &block) or ExpectationHelper.handle_failure(matcher, message, :failure_message_when_negated))
72
+ end
73
+
74
+ def self.does_not_match?(matcher, actual, &block)
75
+ if matcher.respond_to?(:does_not_match?)
76
+ matcher.does_not_match?(actual, &block)
56
77
  else
57
- ::RSpec::Expectations.fail_with message
78
+ !matcher.matches?(actual, &block)
79
+ end
80
+ end
81
+
82
+ def self.verb
83
+ "should not"
84
+ end
85
+
86
+ def self.should_method
87
+ :should_not
88
+ end
89
+
90
+ def self.opposite_should_method
91
+ :should
92
+ end
93
+ end
94
+
95
+ # Wraps a matcher written against one of the legacy protocols in
96
+ # order to present the current protocol.
97
+ #
98
+ # @private
99
+ class LegacyMacherAdapter < Matchers::MatcherDelegator
100
+ def initialize(matcher)
101
+ super
102
+ ::RSpec.warn_deprecation(<<-EOS.gsub(/^\s+\|/, ''), :type => "legacy_matcher")
103
+ |#{matcher.class.name || matcher.inspect} implements a legacy RSpec matcher
104
+ |protocol. For the current protocol you should expose the failure messages
105
+ |via the `failure_message` and `failure_message_when_negated` methods.
106
+ |(Used from #{CallerFilter.first_non_rspec_line})
107
+ EOS
108
+ end
109
+
110
+ def self.wrap(matcher)
111
+ new(matcher) if interface_matches?(matcher)
112
+ end
113
+
114
+ # Starting in RSpec 1.2 (and continuing through all 2.x releases),
115
+ # the failure message protocol was:
116
+ # * `failure_message_for_should`
117
+ # * `failure_message_for_should_not`
118
+ # @private
119
+ class RSpec2 < self
120
+ def failure_message
121
+ base_matcher.failure_message_for_should
122
+ end
123
+
124
+ def failure_message_when_negated
125
+ base_matcher.failure_message_for_should_not
126
+ end
127
+
128
+ def self.interface_matches?(matcher)
129
+ (
130
+ !matcher.respond_to?(:failure_message) &&
131
+ matcher.respond_to?(:failure_message_for_should)
132
+ ) || (
133
+ !matcher.respond_to?(:failure_message_when_negated) &&
134
+ matcher.respond_to?(:failure_message_for_should_not)
135
+ )
136
+ end
137
+ end
138
+
139
+ # Before RSpec 1.2, the failure message protocol was:
140
+ # * `failure_message`
141
+ # * `negative_failure_message`
142
+ # @private
143
+ class RSpec1 < self
144
+ def failure_message
145
+ base_matcher.failure_message
146
+ end
147
+
148
+ def failure_message_when_negated
149
+ base_matcher.negative_failure_message
150
+ end
151
+
152
+ # Note: `failure_message` is part of the RSpec 3 protocol
153
+ # (paired with `failure_message_when_negated`), so we don't check
154
+ # for `failure_message` here.
155
+ def self.interface_matches?(matcher)
156
+ !matcher.respond_to?(:failure_message_when_negated) &&
157
+ matcher.respond_to?(:negative_failure_message)
58
158
  end
59
159
  end
60
160
  end
@@ -0,0 +1,16 @@
1
+ require 'rspec/expectations'
2
+
3
+ Minitest::Test.class_eval do
4
+ include ::RSpec::Matchers
5
+
6
+ def expect(*a, &b)
7
+ assert(true) # so each expectation gets counted in minitest's assertion stats
8
+ super
9
+ end
10
+ end
11
+
12
+ module RSpec::Expectations
13
+ remove_const :ExpectationNotMetError
14
+ ExpectationNotMetError = ::Minitest::Assertion
15
+ end
16
+
@@ -4,38 +4,7 @@ module RSpec
4
4
  # Provides methods for enabling and disabling the available
5
5
  # syntaxes provided by rspec-expectations.
6
6
  module Syntax
7
- extend self
8
-
9
- # @method should
10
- # Passes if `matcher` returns true. Available on every `Object`.
11
- # @example
12
- # actual.should eq expected
13
- # actual.should match /expression/
14
- # @param [Matcher]
15
- # matcher
16
- # @param [String] message optional message to display when the expectation fails
17
- # @return [Boolean] true if the expectation succeeds (else raises)
18
- # @see RSpec::Matchers
19
-
20
- # @method should_not
21
- # Passes if `matcher` returns false. Available on every `Object`.
22
- # @example
23
- # actual.should_not eq expected
24
- # @param [Matcher]
25
- # matcher
26
- # @param [String] message optional message to display when the expectation fails
27
- # @return [Boolean] false if the negative expectation succeeds (else raises)
28
- # @see RSpec::Matchers
29
-
30
- # @method expect
31
- # Supports `expect(actual).to matcher` syntax by wrapping `actual` in an
32
- # `ExpectationTarget`.
33
- # @example
34
- # expect(actual).to eq(expected)
35
- # expect(actual).to_not eq(expected)
36
- # @return [ExpectationTarget]
37
- # @see ExpectationTarget#to
38
- # @see ExpectationTarget#to_not
7
+ module_function
39
8
 
40
9
  # @api private
41
10
  # Determines where we add `should` and `should_not`.
@@ -43,22 +12,44 @@ module RSpec
43
12
  @default_should_host ||= ::Object.ancestors.last
44
13
  end
45
14
 
15
+ # @api private
16
+ # Instructs rspec-expectations to warn on first usage of `should` or `should_not`.
17
+ # Enabled by default. This is largely here to facilitate testing.
18
+ def warn_about_should!
19
+ @warn_about_should = true
20
+ end
21
+
22
+ # @api private
23
+ # Generates a deprecation warning for the given method if no warning
24
+ # has already been issued.
25
+ def warn_about_should_unless_configured(method_name)
26
+ if @warn_about_should
27
+ RSpec.deprecate(
28
+ "Using `#{method_name}` from rspec-expectations' old `:should` syntax without explicitly enabling the syntax",
29
+ :replacement => "the new `:expect` syntax or explicitly enable `:should`"
30
+ )
31
+
32
+ @warn_about_should = false
33
+ end
34
+ end
35
+
46
36
  # @api private
47
37
  # Enables the `should` syntax.
48
38
  def enable_should(syntax_host = default_should_host)
39
+ @warn_about_should = false if syntax_host == default_should_host
49
40
  return if should_enabled?(syntax_host)
50
41
 
51
- syntax_host.module_eval do
42
+ syntax_host.module_exec do
52
43
  def should(matcher=nil, message=nil, &block)
44
+ ::RSpec::Expectations::Syntax.warn_about_should_unless_configured(__method__)
53
45
  ::RSpec::Expectations::PositiveExpectationHandler.handle_matcher(self, matcher, message, &block)
54
46
  end
55
47
 
56
48
  def should_not(matcher=nil, message=nil, &block)
49
+ ::RSpec::Expectations::Syntax.warn_about_should_unless_configured(__method__)
57
50
  ::RSpec::Expectations::NegativeExpectationHandler.handle_matcher(self, matcher, message, &block)
58
51
  end
59
52
  end
60
-
61
- ::RSpec::Expectations::ExpectationTarget.enable_deprecated_should if expect_enabled?
62
53
  end
63
54
 
64
55
  # @api private
@@ -66,12 +57,10 @@ module RSpec
66
57
  def disable_should(syntax_host = default_should_host)
67
58
  return unless should_enabled?(syntax_host)
68
59
 
69
- syntax_host.module_eval do
60
+ syntax_host.module_exec do
70
61
  undef should
71
62
  undef should_not
72
63
  end
73
-
74
- ::RSpec::Expectations::ExpectationTarget.disable_deprecated_should
75
64
  end
76
65
 
77
66
  # @api private
@@ -79,15 +68,11 @@ module RSpec
79
68
  def enable_expect(syntax_host = ::RSpec::Matchers)
80
69
  return if expect_enabled?(syntax_host)
81
70
 
82
- syntax_host.module_eval do
83
- def expect(*target, &target_block)
84
- target << target_block if block_given?
85
- raise ArgumentError.new("You must pass an argument or a block to #expect but not both.") unless target.size == 1
86
- ::RSpec::Expectations::ExpectationTarget.new(target.first)
71
+ syntax_host.module_exec do
72
+ def expect(value=::RSpec::Expectations::ExpectationTarget::UndefinedValue, &block)
73
+ ::RSpec::Expectations::ExpectationTarget.for(value, block)
87
74
  end
88
75
  end
89
-
90
- ::RSpec::Expectations::ExpectationTarget.enable_deprecated_should if should_enabled?
91
76
  end
92
77
 
93
78
  # @api private
@@ -95,11 +80,9 @@ module RSpec
95
80
  def disable_expect(syntax_host = ::RSpec::Matchers)
96
81
  return unless expect_enabled?(syntax_host)
97
82
 
98
- syntax_host.module_eval do
83
+ syntax_host.module_exec do
99
84
  undef expect
100
85
  end
101
-
102
- ::RSpec::Expectations::ExpectationTarget.disable_deprecated_should
103
86
  end
104
87
 
105
88
  # @api private
@@ -113,52 +96,35 @@ module RSpec
113
96
  def expect_enabled?(syntax_host = ::RSpec::Matchers)
114
97
  syntax_host.method_defined?(:expect)
115
98
  end
116
-
117
- # @api private
118
- # Generates a positive expectation expression.
119
- def positive_expression(target_expression, matcher_expression)
120
- expression_generator.positive_expression(target_expression, matcher_expression)
121
- end
122
-
123
- # @api private
124
- # Generates a negative expectation expression.
125
- def negative_expression(target_expression, matcher_expression)
126
- expression_generator.negative_expression(target_expression, matcher_expression)
127
- end
128
-
129
- # @api private
130
- # Selects which expression generator to use based on the configured syntax.
131
- def expression_generator
132
- if expect_enabled?
133
- ExpectExpressionGenerator
134
- else
135
- ShouldExpressionGenerator
136
- end
137
- end
138
-
139
- # @api private
140
- # Generates expectation expressions for the `should` syntax.
141
- module ShouldExpressionGenerator
142
- def self.positive_expression(target_expression, matcher_expression)
143
- "#{target_expression}.should #{matcher_expression}"
144
- end
145
-
146
- def self.negative_expression(target_expression, matcher_expression)
147
- "#{target_expression}.should_not #{matcher_expression}"
148
- end
149
- end
150
-
151
- # @api private
152
- # Generates expectation expressions for the `expect` syntax.
153
- module ExpectExpressionGenerator
154
- def self.positive_expression(target_expression, matcher_expression)
155
- "expect(#{target_expression}).to #{matcher_expression}"
156
- end
157
-
158
- def self.negative_expression(target_expression, matcher_expression)
159
- "expect(#{target_expression}).not_to #{matcher_expression}"
160
- end
161
- end
162
99
  end
163
100
  end
164
101
  end
102
+
103
+ # The legacy `:should` syntax adds the following methods directly to
104
+ # `BasicObject` so that they are available off of any object. Note, however,
105
+ # that this syntax does not always play nice with delegate/proxy objects.
106
+ # We recommend you use the non-monkeypatching `:expect` syntax instead.
107
+ class BasicObject
108
+ # @method should
109
+ # Passes if `matcher` returns true. Available on every `Object`.
110
+ # @example
111
+ # actual.should eq expected
112
+ # actual.should match /expression/
113
+ # @param [Matcher]
114
+ # matcher
115
+ # @param [String] message optional message to display when the expectation fails
116
+ # @return [Boolean] true if the expectation succeeds (else raises)
117
+ # @note This is only available when you have enabled the `:should` syntax.
118
+ # @see RSpec::Matchers
119
+
120
+ # @method should_not
121
+ # Passes if `matcher` returns false. Available on every `Object`.
122
+ # @example
123
+ # actual.should_not eq expected
124
+ # @param [Matcher]
125
+ # matcher
126
+ # @param [String] message optional message to display when the expectation fails
127
+ # @return [Boolean] false if the negative expectation succeeds (else raises)
128
+ # @note This is only available when you have enabled the `:should` syntax.
129
+ # @see RSpec::Matchers
130
+ end
@@ -2,7 +2,7 @@ module RSpec
2
2
  module Expectations
3
3
  # @private
4
4
  module Version
5
- STRING = '2.13.0'
5
+ STRING = '3.0.0'
6
6
  end
7
7
  end
8
8
  end
@@ -1,47 +1,69 @@
1
- require 'rspec/expectations/extensions'
1
+ require 'rspec/support'
2
+ RSpec::Support.require_rspec_support "caller_filter"
3
+ RSpec::Support.require_rspec_support "warnings"
4
+
2
5
  require 'rspec/matchers'
3
- require 'rspec/expectations/expectation_target'
4
- require 'rspec/matchers/configuration'
5
- require 'rspec/expectations/fail_with'
6
- require 'rspec/expectations/errors'
7
- require 'rspec/expectations/deprecation'
8
- require 'rspec/expectations/handler'
9
- require 'rspec/expectations/version'
10
- require 'rspec/expectations/differ'
6
+
7
+ RSpec::Support.define_optimized_require_for_rspec(:expectations) { |f| require_relative(f) }
8
+
9
+ %w[
10
+ expectation_target
11
+ configuration
12
+ fail_with
13
+ handler
14
+ version
15
+ ].each { |file| RSpec::Support.require_rspec_expectations(file) }
11
16
 
12
17
  module RSpec
13
- # RSpec::Expectations adds two instance methods to every object:
18
+ # RSpec::Expectations provides a simple, readable API to express
19
+ # the expected outcomes in a code example. To express an expected
20
+ # outcome, wrap an object or block in `expect`, call `to` or `to_not`
21
+ # (aliased as `not_to`) and pass it a matcher object:
14
22
  #
15
- # should(matcher=nil)
16
- # should_not(matcher=nil)
23
+ # expect(order.total).to eq(Money.new(5.55, :USD))
24
+ # expect(list).to include(user)
25
+ # expect(message).not_to match(/foo/)
26
+ # expect { do_something }.to raise_error
17
27
  #
18
- # Both methods take an optional matcher object (See
19
- # [RSpec::Matchers](../RSpec/Matchers)). When `should` is invoked with a
20
- # matcher, it turns around and calls `matcher.matches?(self)`. For example,
28
+ # The last form (the block form) is needed to match against ruby constructs
29
+ # that are not objects, but can only be observed when executing a block
30
+ # of code. This includes raising errors, throwing symbols, yielding,
31
+ # and changing values.
32
+ #
33
+ # When `expect(...).to` is invoked with a matcher, it turns around
34
+ # and calls `matcher.matches?(<object wrapped by expect>)`. For example,
21
35
  # in the expression:
22
36
  #
23
- # order.total.should eq(Money.new(5.55, :USD))
37
+ # expect(order.total).to eq(Money.new(5.55, :USD))
24
38
  #
25
- # the `should` method invokes the equivalent of `eq.matches?(order.total)`. If
26
- # `matches?` returns true, the expectation is met and execution continues. If
27
- # `false`, then the spec fails with the message returned by
28
- # `eq.failure_message_for_should`.
39
+ # ...`eq(Money.new(5.55, :USD))` returns a matcher object, and it results
40
+ # in the equivalent of `eq.matches?(order.total)`. If `matches?` returns
41
+ # `true`, the expectation is met and execution continues. If `false`, then
42
+ # the spec fails with the message returned by `eq.failure_message`.
29
43
  #
30
44
  # Given the expression:
31
45
  #
32
- # order.entries.should_not include(entry)
46
+ # expect(order.entries).not_to include(entry)
33
47
  #
34
- # the `should_not` method invokes the equivalent of
48
+ # ...the `not_to` method (also available as `to_not`) invokes the equivalent of
35
49
  # `include.matches?(order.entries)`, but it interprets `false` as success, and
36
50
  # `true` as a failure, using the message generated by
37
- # `eq.failure_message_for_should_not`.
51
+ # `eq.failure_message_when_negated`.
38
52
  #
39
53
  # rspec-expectations ships with a standard set of useful matchers, and writing
40
- # your own matchers is quite simple.
54
+ # your own matchers is quite simple.
41
55
  #
42
56
  # See [RSpec::Matchers](../RSpec/Matchers) for more information about the
43
57
  # built-in matchers that ship with rspec-expectations, and how to write your
44
58
  # own custom matchers.
45
59
  module Expectations
60
+ # Exception raised when an expectation fails.
61
+ #
62
+ # @note We subclass Exception so that in a stub implementation if
63
+ # the user sets an expectation, it can't be caught in their
64
+ # code by a bare `rescue`.
65
+ # @api public
66
+ ExpectationNotMetError = Class.new(::Exception)
46
67
  end
47
68
  end
69
+
@@ -0,0 +1,41 @@
1
+ module RSpec
2
+ module Matchers
3
+ # Decorator that wraps a matcher and overrides `description`
4
+ # using the provided block in order to support an alias
5
+ # of a matcher. This is intended for use when composing
6
+ # matchers, so that you can use an expression like
7
+ # `include( a_value_within(0.1).of(3) )` rather than
8
+ # `include( be_within(0.1).of(3) )`, and have the corresponding
9
+ # description read naturally.
10
+ #
11
+ # @api private
12
+ class AliasedMatcher < MatcherDelegator
13
+ def initialize(base_matcher, description_block)
14
+ @description_block = description_block
15
+ super(base_matcher)
16
+ end
17
+
18
+ # Forward messages on to the wrapped matcher.
19
+ # Since many matchers provide a fluent interface
20
+ # (e.g. `a_value_within(0.1).of(3)`), we need to wrap
21
+ # the returned value if it responds to `description`,
22
+ # so that our override can be applied when it is eventually
23
+ # used.
24
+ def method_missing(*)
25
+ return_val = super
26
+ return return_val unless return_val.respond_to?(:description)
27
+ AliasedMatcher.new(return_val, @description_block)
28
+ end
29
+
30
+ # Provides the description of the aliased matcher. Aliased matchers
31
+ # are designed to behave identically to the original matcher except
32
+ # for this method. The description is different to reflect the aliased
33
+ # name.
34
+ #
35
+ # @api private
36
+ def description
37
+ @description_block.call(super)
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,78 @@
1
+ module RSpec
2
+ module Matchers
3
+ module BuiltIn
4
+ # @api private
5
+ # Provides the implementation for `all`.
6
+ # Not intended to be instantiated directly.
7
+ class All < BaseMatcher
8
+
9
+ # @private
10
+ attr_reader :matcher, :failed_objects
11
+
12
+ def initialize(matcher)
13
+ @matcher = matcher
14
+ @failed_objects = {}
15
+ end
16
+
17
+ # @private
18
+ def does_not_match?(actual)
19
+ raise NotImplementedError, '`expect().not_to all( matcher )` is not supported.'
20
+ end
21
+
22
+ # @api private
23
+ # @return [String]
24
+ def failure_message
25
+ all_messages = [improve_hash_formatting(super)]
26
+ failed_objects.each do |index, matcher_failure_message|
27
+ all_messages << failure_message_for_item(index, matcher_failure_message)
28
+ end
29
+ all_messages.join("\n\n")
30
+ end
31
+
32
+ # @api private
33
+ # @return [String]
34
+ def description
35
+ described_items = surface_descriptions_in(matcher)
36
+ improve_hash_formatting "all#{to_sentence(described_items)}"
37
+ end
38
+
39
+ private
40
+
41
+ def match(_, actual)
42
+ index_failed_objects
43
+ failed_objects.empty?
44
+ end
45
+
46
+ def index_failed_objects
47
+ actual.each_with_index do |actual_item, index|
48
+ cloned_matcher = matcher.clone
49
+ matches = cloned_matcher.matches?(actual_item)
50
+ failed_objects[index] = cloned_matcher.failure_message unless matches
51
+ end
52
+ end
53
+
54
+ def failure_message_for_item(index, failure_message)
55
+ failure_message = indent_multiline_message( add_new_line_if_needed(failure_message) )
56
+ indent_multiline_message("object at index #{index} failed to match:#{failure_message}")
57
+ end
58
+
59
+ def add_new_line_if_needed(message)
60
+ message.start_with?("\n") ? message : "\n#{message}"
61
+ end
62
+
63
+ def indent_multiline_message(message)
64
+ message = message.sub(/\n+\z/, '')
65
+ message.lines.map do |line|
66
+ line =~ /\S/ ? ' ' + line : line
67
+ end.join
68
+ end
69
+
70
+ def initialize_copy(other)
71
+ @matcher = @matcher.clone
72
+ super
73
+ end
74
+
75
+ end
76
+ end
77
+ end
78
+ end