rspec-expectations 2.14.0 → 3.13.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 (155) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data/.document +1 -1
  4. data/.yardopts +1 -1
  5. data/Changelog.md +976 -25
  6. data/{License.txt → LICENSE.md} +5 -3
  7. data/README.md +162 -26
  8. data/lib/rspec/expectations/block_snippet_extractor.rb +253 -0
  9. data/lib/rspec/expectations/configuration.rb +230 -0
  10. data/lib/rspec/expectations/expectation_target.rb +127 -51
  11. data/lib/rspec/expectations/fail_with.rb +17 -57
  12. data/lib/rspec/expectations/failure_aggregator.rb +229 -0
  13. data/lib/rspec/expectations/handler.rb +146 -32
  14. data/lib/rspec/expectations/minitest_integration.rb +58 -0
  15. data/lib/rspec/expectations/syntax.rb +68 -100
  16. data/lib/rspec/expectations/version.rb +1 -1
  17. data/lib/rspec/expectations.rb +58 -23
  18. data/lib/rspec/matchers/aliased_matcher.rb +116 -0
  19. data/lib/rspec/matchers/built_in/all.rb +86 -0
  20. data/lib/rspec/matchers/built_in/base_matcher.rb +191 -20
  21. data/lib/rspec/matchers/built_in/be.rb +114 -114
  22. data/lib/rspec/matchers/built_in/be_between.rb +77 -0
  23. data/lib/rspec/matchers/built_in/be_instance_of.rb +15 -4
  24. data/lib/rspec/matchers/built_in/be_kind_of.rb +10 -1
  25. data/lib/rspec/matchers/built_in/be_within.rb +35 -18
  26. data/lib/rspec/matchers/built_in/change.rb +389 -80
  27. data/lib/rspec/matchers/built_in/compound.rb +290 -0
  28. data/lib/rspec/matchers/built_in/contain_exactly.rb +310 -0
  29. data/lib/rspec/matchers/built_in/count_expectation.rb +169 -0
  30. data/lib/rspec/matchers/built_in/cover.rb +3 -0
  31. data/lib/rspec/matchers/built_in/eq.rb +30 -8
  32. data/lib/rspec/matchers/built_in/eql.rb +23 -8
  33. data/lib/rspec/matchers/built_in/equal.rb +55 -22
  34. data/lib/rspec/matchers/built_in/exist.rb +74 -10
  35. data/lib/rspec/matchers/built_in/has.rb +141 -22
  36. data/lib/rspec/matchers/built_in/have_attributes.rb +114 -0
  37. data/lib/rspec/matchers/built_in/include.rb +184 -32
  38. data/lib/rspec/matchers/built_in/match.rb +95 -1
  39. data/lib/rspec/matchers/built_in/operators.rb +128 -0
  40. data/lib/rspec/matchers/built_in/output.rb +207 -0
  41. data/lib/rspec/matchers/built_in/raise_error.rb +192 -44
  42. data/lib/rspec/matchers/built_in/respond_to.rb +154 -28
  43. data/lib/rspec/matchers/built_in/satisfy.rb +39 -9
  44. data/lib/rspec/matchers/built_in/start_or_end_with.rb +94 -0
  45. data/lib/rspec/matchers/built_in/throw_symbol.rb +58 -14
  46. data/lib/rspec/matchers/built_in/yield.rb +240 -161
  47. data/lib/rspec/matchers/built_in.rb +47 -33
  48. data/lib/rspec/matchers/composable.rb +171 -0
  49. data/lib/rspec/matchers/dsl.rb +531 -10
  50. data/lib/rspec/matchers/english_phrasing.rb +58 -0
  51. data/lib/rspec/matchers/fail_matchers.rb +42 -0
  52. data/lib/rspec/matchers/generated_descriptions.rb +14 -8
  53. data/lib/rspec/matchers/matcher_delegator.rb +61 -0
  54. data/lib/rspec/matchers/matcher_protocol.rb +105 -0
  55. data/lib/rspec/matchers/multi_matcher_diff.rb +82 -0
  56. data/lib/rspec/matchers.rb +520 -173
  57. data.tar.gz.sig +0 -0
  58. metadata +141 -242
  59. metadata.gz.sig +2 -0
  60. data/features/README.md +0 -48
  61. data/features/Upgrade.md +0 -53
  62. data/features/built_in_matchers/README.md +0 -90
  63. data/features/built_in_matchers/be.feature +0 -175
  64. data/features/built_in_matchers/be_within.feature +0 -48
  65. data/features/built_in_matchers/cover.feature +0 -47
  66. data/features/built_in_matchers/end_with.feature +0 -48
  67. data/features/built_in_matchers/equality.feature +0 -139
  68. data/features/built_in_matchers/exist.feature +0 -45
  69. data/features/built_in_matchers/expect_change.feature +0 -59
  70. data/features/built_in_matchers/expect_error.feature +0 -144
  71. data/features/built_in_matchers/have.feature +0 -109
  72. data/features/built_in_matchers/include.feature +0 -174
  73. data/features/built_in_matchers/match.feature +0 -52
  74. data/features/built_in_matchers/operators.feature +0 -227
  75. data/features/built_in_matchers/predicates.feature +0 -137
  76. data/features/built_in_matchers/respond_to.feature +0 -84
  77. data/features/built_in_matchers/satisfy.feature +0 -33
  78. data/features/built_in_matchers/start_with.feature +0 -48
  79. data/features/built_in_matchers/throw_symbol.feature +0 -91
  80. data/features/built_in_matchers/types.feature +0 -116
  81. data/features/built_in_matchers/yield.feature +0 -161
  82. data/features/custom_matchers/access_running_example.feature +0 -53
  83. data/features/custom_matchers/define_diffable_matcher.feature +0 -27
  84. data/features/custom_matchers/define_matcher.feature +0 -368
  85. data/features/custom_matchers/define_matcher_outside_rspec.feature +0 -38
  86. data/features/custom_matchers/define_matcher_with_fluent_interface.feature +0 -24
  87. data/features/customized_message.feature +0 -22
  88. data/features/diffing.feature +0 -85
  89. data/features/implicit_docstrings.feature +0 -52
  90. data/features/step_definitions/additional_cli_steps.rb +0 -22
  91. data/features/support/env.rb +0 -14
  92. data/features/syntax_configuration.feature +0 -71
  93. data/features/test_frameworks/test_unit.feature +0 -44
  94. data/lib/rspec/expectations/deprecation.rb +0 -17
  95. data/lib/rspec/expectations/differ.rb +0 -133
  96. data/lib/rspec/expectations/errors.rb +0 -9
  97. data/lib/rspec/expectations/extensions/array.rb +0 -9
  98. data/lib/rspec/expectations/extensions/object.rb +0 -29
  99. data/lib/rspec/expectations/extensions.rb +0 -2
  100. data/lib/rspec/matchers/be_close.rb +0 -9
  101. data/lib/rspec/matchers/built_in/have.rb +0 -124
  102. data/lib/rspec/matchers/built_in/match_array.rb +0 -51
  103. data/lib/rspec/matchers/built_in/start_and_end_with.rb +0 -48
  104. data/lib/rspec/matchers/compatibility.rb +0 -14
  105. data/lib/rspec/matchers/configuration.rb +0 -108
  106. data/lib/rspec/matchers/extensions/instance_eval_with_args.rb +0 -39
  107. data/lib/rspec/matchers/matcher.rb +0 -300
  108. data/lib/rspec/matchers/method_missing.rb +0 -12
  109. data/lib/rspec/matchers/operator_matcher.rb +0 -109
  110. data/lib/rspec/matchers/pretty.rb +0 -70
  111. data/lib/rspec/matchers/test_unit_integration.rb +0 -11
  112. data/lib/rspec-expectations.rb +0 -1
  113. data/spec/rspec/expectations/differ_spec.rb +0 -192
  114. data/spec/rspec/expectations/expectation_target_spec.rb +0 -82
  115. data/spec/rspec/expectations/extensions/kernel_spec.rb +0 -67
  116. data/spec/rspec/expectations/fail_with_spec.rb +0 -114
  117. data/spec/rspec/expectations/handler_spec.rb +0 -227
  118. data/spec/rspec/expectations/syntax_spec.rb +0 -139
  119. data/spec/rspec/matchers/base_matcher_spec.rb +0 -62
  120. data/spec/rspec/matchers/be_close_spec.rb +0 -22
  121. data/spec/rspec/matchers/be_instance_of_spec.rb +0 -63
  122. data/spec/rspec/matchers/be_kind_of_spec.rb +0 -41
  123. data/spec/rspec/matchers/be_spec.rb +0 -516
  124. data/spec/rspec/matchers/be_within_spec.rb +0 -137
  125. data/spec/rspec/matchers/change_spec.rb +0 -553
  126. data/spec/rspec/matchers/configuration_spec.rb +0 -206
  127. data/spec/rspec/matchers/cover_spec.rb +0 -69
  128. data/spec/rspec/matchers/description_generation_spec.rb +0 -190
  129. data/spec/rspec/matchers/dsl_spec.rb +0 -57
  130. data/spec/rspec/matchers/eq_spec.rb +0 -60
  131. data/spec/rspec/matchers/eql_spec.rb +0 -41
  132. data/spec/rspec/matchers/equal_spec.rb +0 -78
  133. data/spec/rspec/matchers/exist_spec.rb +0 -124
  134. data/spec/rspec/matchers/has_spec.rb +0 -122
  135. data/spec/rspec/matchers/have_spec.rb +0 -455
  136. data/spec/rspec/matchers/include_matcher_integration_spec.rb +0 -30
  137. data/spec/rspec/matchers/include_spec.rb +0 -531
  138. data/spec/rspec/matchers/match_array_spec.rb +0 -194
  139. data/spec/rspec/matchers/match_spec.rb +0 -61
  140. data/spec/rspec/matchers/matcher_spec.rb +0 -471
  141. data/spec/rspec/matchers/matchers_spec.rb +0 -37
  142. data/spec/rspec/matchers/method_missing_spec.rb +0 -28
  143. data/spec/rspec/matchers/operator_matcher_spec.rb +0 -223
  144. data/spec/rspec/matchers/raise_error_spec.rb +0 -485
  145. data/spec/rspec/matchers/respond_to_spec.rb +0 -292
  146. data/spec/rspec/matchers/satisfy_spec.rb +0 -44
  147. data/spec/rspec/matchers/start_with_end_with_spec.rb +0 -186
  148. data/spec/rspec/matchers/throw_symbol_spec.rb +0 -116
  149. data/spec/rspec/matchers/yield_spec.rb +0 -514
  150. data/spec/spec_helper.rb +0 -54
  151. data/spec/support/classes.rb +0 -56
  152. data/spec/support/in_sub_process.rb +0 -38
  153. data/spec/support/matchers.rb +0 -22
  154. data/spec/support/ruby_version.rb +0 -10
  155. data/spec/support/shared_examples.rb +0 -13
@@ -4,27 +4,46 @@ module RSpec
4
4
  # @api private
5
5
  #
6
6
  # Used _internally_ as a base class for matchers that ship with
7
- # rspec-expectations.
7
+ # rspec-expectations and rspec-rails.
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
- include RSpec::Matchers::Pretty
15
+ include RSpec::Matchers::Composable
16
16
 
17
+ # @api private
18
+ # Used to detect when no arg is passed to `initialize`.
19
+ # `nil` cannot be used because it's a valid value to pass.
20
+ UNDEFINED = Object.new.freeze
21
+
22
+ # @private
17
23
  attr_reader :actual, :expected, :rescued_exception
18
24
 
19
- def initialize(expected = nil)
20
- @expected = expected
25
+ # @private
26
+ attr_writer :matcher_name
27
+
28
+ def initialize(expected=UNDEFINED)
29
+ @expected = expected unless UNDEFINED.equal?(expected)
21
30
  end
22
31
 
32
+ # @api private
33
+ # Indicates if the match is successful. Delegates to `match`, which
34
+ # should be defined on a subclass. Takes care of consistently
35
+ # initializing the `actual` attribute.
23
36
  def matches?(actual)
24
37
  @actual = actual
25
38
  match(expected, actual)
26
39
  end
27
40
 
41
+ # @api private
42
+ # Used to wrap a block of code that will indicate failure by
43
+ # raising one of the named exceptions.
44
+ #
45
+ # This is used by rspec-rails for some of its matchers that
46
+ # wrap rails' assertions.
28
47
  def match_unless_raises(*exceptions)
29
48
  exceptions.unshift Exception if exceptions.empty?
30
49
  begin
@@ -35,33 +54,185 @@ module RSpec
35
54
  end
36
55
  end
37
56
 
38
- def failure_message_for_should
39
- assert_ivars :@actual, :@expected
40
- "expected #{@actual.inspect} to #{name_to_sentence}#{expected_to_sentence}"
57
+ # @api private
58
+ # Generates a description using {EnglishPhrasing}.
59
+ # @return [String]
60
+ def description
61
+ desc = EnglishPhrasing.split_words(self.class.matcher_name)
62
+ desc << EnglishPhrasing.list(@expected) if defined?(@expected)
63
+ desc
41
64
  end
42
65
 
43
- def failure_message_for_should_not
44
- assert_ivars :@actual, :@expected
45
- "expected #{@actual.inspect} not to #{name_to_sentence}#{expected_to_sentence}"
66
+ # @api private
67
+ # Matchers are not diffable by default. Override this to make your
68
+ # subclass diffable.
69
+ def diffable?
70
+ false
46
71
  end
47
72
 
48
- def description
49
- expected ? "#{name_to_sentence} #{@expected.inspect}" : name_to_sentence
73
+ # @api private
74
+ # Most matchers are value matchers (i.e. meant to work with `expect(value)`)
75
+ # rather than block matchers (i.e. meant to work with `expect { }`), so
76
+ # this defaults to false. Block matchers must override this to return true.
77
+ def supports_block_expectations?
78
+ false
50
79
  end
51
80
 
52
- def diffable?
81
+ # @private
82
+ def supports_value_expectations?
83
+ true
84
+ end
85
+
86
+ # @api private
87
+ def expects_call_stack_jump?
53
88
  false
54
89
  end
55
90
 
56
- def ==(other)
57
- matches?(other)
91
+ # @private
92
+ def expected_formatted
93
+ RSpec::Support::ObjectFormatter.format(@expected)
58
94
  end
59
95
 
60
- private
96
+ # @private
97
+ def actual_formatted
98
+ RSpec::Support::ObjectFormatter.format(@actual)
99
+ end
61
100
 
62
- def assert_ivars *ivars
63
- raise "#{self.class.name} needs to supply #{to_sentence ivars}" unless ivars.all? { |v| instance_variables.map(&:intern).include? v }
101
+ # @private
102
+ def self.matcher_name
103
+ @matcher_name ||= underscore(name.split('::').last)
64
104
  end
105
+
106
+ # @private
107
+ def matcher_name
108
+ if defined?(@matcher_name)
109
+ @matcher_name
110
+ else
111
+ self.class.matcher_name
112
+ end
113
+ end
114
+
115
+ # @private
116
+ # Borrowed from ActiveSupport.
117
+ def self.underscore(camel_cased_word)
118
+ word = camel_cased_word.to_s.dup
119
+ word.gsub!(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
120
+ word.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
121
+ word.tr!('-', '_')
122
+ word.downcase!
123
+ word
124
+ end
125
+ private_class_method :underscore
126
+
127
+ private
128
+
129
+ def assert_ivars(*expected_ivars)
130
+ return unless (expected_ivars - present_ivars).any?
131
+ ivar_list = EnglishPhrasing.list(expected_ivars)
132
+ raise "#{self.class.name} needs to supply#{ivar_list}"
133
+ end
134
+
135
+ if RUBY_VERSION.to_f < 1.9
136
+ # :nocov:
137
+ def present_ivars
138
+ instance_variables.map(&:to_sym)
139
+ end
140
+ # :nocov:
141
+ else
142
+ alias present_ivars instance_variables
143
+ end
144
+
145
+ # @private
146
+ module HashFormatting
147
+ # `{ :a => 5, :b => 2 }.inspect` produces:
148
+ #
149
+ # {:a=>5, :b=>2}
150
+ #
151
+ # ...but it looks much better as:
152
+ #
153
+ # {:a => 5, :b => 2}
154
+ #
155
+ # This is idempotent and safe to run on a string multiple times.
156
+ def improve_hash_formatting(inspect_string)
157
+ inspect_string.gsub(/(\S)=>(\S)/, '\1 => \2')
158
+ end
159
+ module_function :improve_hash_formatting
160
+ end
161
+
162
+ include HashFormatting
163
+
164
+ # @private
165
+ module StringEncodingFormatting
166
+ # @api private
167
+ # @return [Boolean] True if the actual and expected string encoding are different.
168
+ # i.e. the failure may be related to encoding differences and the encoding
169
+ # should be shown to the user. false otherwise.
170
+ if String.method_defined?(:encoding)
171
+ def string_encoding_differs?
172
+ actual.is_a?(String) && expected.is_a?(String) && actual.encoding != expected.encoding
173
+ end
174
+ else
175
+ # @api private
176
+ # @return [Boolean] False always as the curent Ruby version does not support String encoding
177
+ def string_encoding_differs?
178
+ false
179
+ end
180
+ end
181
+ module_function :string_encoding_differs?
182
+
183
+ if String.method_defined?(:encoding)
184
+ # @api private
185
+ # Formats a String's encoding as a human readable string
186
+ # @param value [String]
187
+ # @return [String]
188
+ def format_encoding(value)
189
+ "#<Encoding:#{value.encoding.name}>"
190
+ end
191
+ else
192
+ # @api private
193
+ # Formats a String's encoding as a human readable string
194
+ # @param _value [String]
195
+ # @return [nil] nil as the curent Ruby version does not support String encoding
196
+ def format_encoding(_value)
197
+ nil
198
+ end
199
+ end
200
+ module_function :format_encoding
201
+ end
202
+
203
+ include StringEncodingFormatting
204
+
205
+ # @api private
206
+ # Provides default implementations of failure messages, based on the `description`.
207
+ module DefaultFailureMessages
208
+ # @api private
209
+ # Provides a good generic failure message. Based on `description`.
210
+ # When subclassing, if you are not satisfied with this failure message
211
+ # you often only need to override `description`.
212
+ # @return [String]
213
+ def failure_message
214
+ "expected #{description_of @actual} to #{description}".dup
215
+ end
216
+
217
+ # @api private
218
+ # Provides a good generic negative failure message. Based on `description`.
219
+ # When subclassing, if you are not satisfied with this failure message
220
+ # you often only need to override `description`.
221
+ # @return [String]
222
+ def failure_message_when_negated
223
+ "expected #{description_of @actual} not to #{description}".dup
224
+ end
225
+
226
+ # @private
227
+ def self.has_default_failure_messages?(matcher)
228
+ matcher.method(:failure_message).owner == self &&
229
+ matcher.method(:failure_message_when_negated).owner == self
230
+ rescue NameError
231
+ false
232
+ end
233
+ end
234
+
235
+ include DefaultFailureMessages
65
236
  end
66
237
  end
67
238
  end
@@ -1,74 +1,78 @@
1
- require 'rspec/matchers/dsl'
2
-
3
1
  module RSpec
4
2
  module Matchers
5
3
  module BuiltIn
6
- class BeTrue < BaseMatcher
7
- def match(_, actual)
8
- !!actual
4
+ # @api private
5
+ # Provides the implementation for `be_truthy`.
6
+ # Not intended to be instantiated directly.
7
+ class BeTruthy < BaseMatcher
8
+ # @api private
9
+ # @return [String]
10
+ def failure_message
11
+ "expected: truthy value\n got: #{actual_formatted}"
9
12
  end
10
13
 
11
- def failure_message_for_should
12
- "expected: true value\n got: #{actual.inspect}"
14
+ # @api private
15
+ # @return [String]
16
+ def failure_message_when_negated
17
+ "expected: falsey value\n got: #{actual_formatted}"
13
18
  end
14
19
 
15
- def failure_message_for_should_not
16
- "expected: non-true value\n got: #{actual.inspect}"
17
- end
18
- end
20
+ private
19
21
 
20
- class BeFalse < BaseMatcher
21
22
  def match(_, actual)
22
- !actual
23
+ !!actual
23
24
  end
25
+ end
24
26
 
25
- def failure_message_for_should
26
- "expected: false value\n got: #{actual.inspect}"
27
+ # @api private
28
+ # Provides the implementation for `be_falsey`.
29
+ # Not intended to be instantiated directly.
30
+ class BeFalsey < BaseMatcher
31
+ # @api private
32
+ # @return [String]
33
+ def failure_message
34
+ "expected: falsey value\n got: #{actual_formatted}"
27
35
  end
28
36
 
29
- def failure_message_for_should_not
30
- "expected: non-false value\n got: #{actual.inspect}"
37
+ # @api private
38
+ # @return [String]
39
+ def failure_message_when_negated
40
+ "expected: truthy value\n got: #{actual_formatted}"
31
41
  end
32
- end
33
42
 
34
- class BeNil < BaseMatcher
43
+ private
44
+
35
45
  def match(_, actual)
36
- actual.nil?
46
+ !actual
37
47
  end
48
+ end
38
49
 
39
- def failure_message_for_should
40
- "expected: nil\n got: #{actual.inspect}"
50
+ # @api private
51
+ # Provides the implementation for `be_nil`.
52
+ # Not intended to be instantiated directly.
53
+ class BeNil < BaseMatcher
54
+ # @api private
55
+ # @return [String]
56
+ def failure_message
57
+ "expected: nil\n got: #{actual_formatted}"
41
58
  end
42
59
 
43
- def failure_message_for_should_not
60
+ # @api private
61
+ # @return [String]
62
+ def failure_message_when_negated
44
63
  "expected: not nil\n got: nil"
45
64
  end
46
- end
47
65
 
48
- class Be < BaseMatcher
49
- def initialize(*args, &block)
50
- @args = args
51
- end
66
+ private
52
67
 
53
68
  def match(_, actual)
54
- !!actual
55
- end
56
-
57
- def failure_message_for_should
58
- "expected #{@actual.inspect} to evaluate to true"
59
- end
60
-
61
- def failure_message_for_should_not
62
- "expected #{@actual.inspect} to evaluate to false"
63
- end
64
-
65
- [:==, :<, :<=, :>=, :>, :===, :=~].each do |operator|
66
- define_method operator do |operand|
67
- BeComparedTo.new(operand, operator)
68
- end
69
+ actual.nil?
69
70
  end
71
+ end
70
72
 
71
- private
73
+ # @private
74
+ module BeHelpers
75
+ private
72
76
 
73
77
  def args_to_s
74
78
  @args.empty? ? "" : parenthesize(inspected_args.join(', '))
@@ -79,111 +83,107 @@ module RSpec
79
83
  end
80
84
 
81
85
  def inspected_args
82
- @args.collect{|a| a.inspect}
86
+ @args.map { |a| RSpec::Support::ObjectFormatter.format(a) }
83
87
  end
84
88
 
85
89
  def expected_to_sentence
86
- split_words(@expected)
90
+ EnglishPhrasing.split_words(@expected)
87
91
  end
88
92
 
89
93
  def args_to_sentence
90
- to_sentence(@args)
94
+ EnglishPhrasing.list(@args)
91
95
  end
92
96
  end
93
97
 
94
- class BeComparedTo < Be
95
- def initialize(operand, operator)
96
- @expected, @operator = operand, operator
97
- @args = []
98
- end
99
-
100
- def matches?(actual)
101
- @actual = actual
102
- @actual.__send__ @operator, @expected
103
- end
98
+ # @api private
99
+ # Provides the implementation for `be`.
100
+ # Not intended to be instantiated directly.
101
+ class Be < BaseMatcher
102
+ include BeHelpers
104
103
 
105
- def failure_message_for_should
106
- "expected: #{@operator} #{@expected.inspect}\n got: #{@operator.to_s.gsub(/./, ' ')} #{@actual.inspect}"
104
+ def initialize(*args)
105
+ @args = args
107
106
  end
108
107
 
109
- def failure_message_for_should_not
110
- message = <<-MESSAGE
111
- `#{negative_expectation_expression}` not only FAILED,
112
- it is a bit confusing.
113
- MESSAGE
114
-
115
- raise message << ([:===,:==].include?(@operator) ?
116
- "It might be more clearly expressed without the \"be\"?" :
117
- "It might be more clearly expressed in the positive?")
108
+ # @api private
109
+ # @return [String]
110
+ def failure_message
111
+ "expected #{actual_formatted} to evaluate to true"
118
112
  end
119
113
 
120
- def description
121
- "be #{@operator} #{expected_to_sentence}#{args_to_sentence}"
114
+ # @api private
115
+ # @return [String]
116
+ def failure_message_when_negated
117
+ "expected #{actual_formatted} to evaluate to false"
122
118
  end
123
119
 
124
- def negative_expectation_expression
125
- Expectations::Syntax.negative_expression("actual", "be #{@operator} #{@expected}")
126
- end
127
- end
128
-
129
- class BePredicate < Be
130
- def initialize(*args, &block)
131
- @expected = parse_expected(args.shift)
132
- @args = args
133
- @block = block
120
+ [:==, :<, :<=, :>=, :>, :===, :=~].each do |operator|
121
+ define_method operator do |operand|
122
+ BeComparedTo.new(operand, operator)
123
+ end
134
124
  end
135
125
 
136
- def matches?(actual)
137
- @actual = actual
138
- begin
139
- return @result = actual.__send__(predicate, *@args, &@block)
140
- rescue NameError => predicate_missing_error
141
- "this needs to be here or rcov will not count this branch even though it's executed in a code example"
142
- end
126
+ private
143
127
 
144
- begin
145
- return @result = actual.__send__(present_tense_predicate, *@args, &@block)
146
- rescue NameError
147
- raise predicate_missing_error
148
- end
128
+ def match(_, actual)
129
+ !!actual
149
130
  end
131
+ end
150
132
 
151
- alias === matches?
133
+ # @api private
134
+ # Provides the implementation of `be <operator> value`.
135
+ # Not intended to be instantiated directly.
136
+ class BeComparedTo < BaseMatcher
137
+ include BeHelpers
152
138
 
153
- def failure_message_for_should
154
- "expected #{predicate}#{args_to_s} to return true, got #{@result.inspect}"
139
+ def initialize(operand, operator)
140
+ @expected = operand
141
+ @operator = operator
142
+ @args = []
155
143
  end
156
144
 
157
- def failure_message_for_should_not
158
- "expected #{predicate}#{args_to_s} to return false, got #{@result.inspect}"
145
+ def matches?(actual)
146
+ perform_match(actual)
147
+ rescue ArgumentError, NoMethodError
148
+ false
159
149
  end
160
150
 
161
- def description
162
- "#{prefix_to_sentence}#{expected_to_sentence}#{args_to_sentence}"
151
+ def does_not_match?(actual)
152
+ !perform_match(actual)
153
+ rescue ArgumentError, NoMethodError
154
+ false
163
155
  end
164
156
 
165
- private
166
-
167
- def predicate
168
- "#{@expected}?".to_sym
157
+ # @api private
158
+ # @return [String]
159
+ def failure_message
160
+ "expected: #{@operator} #{expected_formatted}\n" \
161
+ " got: #{@operator.to_s.gsub(/./, ' ')} #{actual_formatted}"
169
162
  end
170
163
 
171
- def present_tense_predicate
172
- "#{@expected}s?".to_sym
164
+ # @api private
165
+ # @return [String]
166
+ def failure_message_when_negated
167
+ message = "`expect(#{actual_formatted}).not_to " \
168
+ "be #{@operator} #{expected_formatted}`"
169
+ if [:<, :>, :<=, :>=].include?(@operator)
170
+ message + " not only FAILED, it is a bit confusing."
171
+ else
172
+ message
173
+ end
173
174
  end
174
175
 
175
- def parse_expected(expected)
176
- @prefix, expected = prefix_and_expected(expected)
177
- expected
176
+ # @api private
177
+ # @return [String]
178
+ def description
179
+ "be #{@operator} #{expected_to_sentence}#{args_to_sentence}"
178
180
  end
179
181
 
180
- def prefix_and_expected(symbol)
181
- symbol.to_s =~ /^(be_(an?_)?)(.*)/
182
- return $1, $3
183
- end
182
+ private
184
183
 
185
- def prefix_to_sentence
186
- split_words(@prefix)
184
+ def perform_match(actual)
185
+ @actual = actual
186
+ @actual.__send__ @operator, @expected
187
187
  end
188
188
  end
189
189
  end
@@ -0,0 +1,77 @@
1
+ module RSpec
2
+ module Matchers
3
+ module BuiltIn
4
+ # @api private
5
+ # Provides the implementation for `be_between`.
6
+ # Not intended to be instantiated directly.
7
+ class BeBetween < BaseMatcher
8
+ def initialize(min, max)
9
+ @min, @max = min, max
10
+ inclusive
11
+ end
12
+
13
+ # @api public
14
+ # Makes the between comparison inclusive.
15
+ #
16
+ # @example
17
+ # expect(3).to be_between(2, 3).inclusive
18
+ #
19
+ # @note The matcher is inclusive by default; this simply provides
20
+ # a way to be more explicit about it.
21
+ def inclusive
22
+ @less_than_operator = :<=
23
+ @greater_than_operator = :>=
24
+ @mode = :inclusive
25
+ self
26
+ end
27
+
28
+ # @api public
29
+ # Makes the between comparison exclusive.
30
+ #
31
+ # @example
32
+ # expect(3).to be_between(2, 4).exclusive
33
+ def exclusive
34
+ @less_than_operator = :<
35
+ @greater_than_operator = :>
36
+ @mode = :exclusive
37
+ self
38
+ end
39
+
40
+ # @api private
41
+ # @return [Boolean]
42
+ def matches?(actual)
43
+ @actual = actual
44
+ comparable? && compare
45
+ rescue ArgumentError
46
+ false
47
+ end
48
+
49
+ # @api private
50
+ # @return [String]
51
+ def failure_message
52
+ "#{super}#{not_comparable_clause}"
53
+ end
54
+
55
+ # @api private
56
+ # @return [String]
57
+ def description
58
+ "be between #{description_of @min} and #{description_of @max} (#{@mode})"
59
+ end
60
+
61
+ private
62
+
63
+ def comparable?
64
+ @actual.respond_to?(@less_than_operator) && @actual.respond_to?(@greater_than_operator)
65
+ end
66
+
67
+ def not_comparable_clause
68
+ ", but it does not respond to `#{@less_than_operator}` and `#{@greater_than_operator}`" unless comparable?
69
+ end
70
+
71
+ def compare
72
+ @actual.__send__(@greater_than_operator, @min) && @actual.__send__(@less_than_operator, @max)
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -1,14 +1,25 @@
1
1
  module RSpec
2
2
  module Matchers
3
3
  module BuiltIn
4
+ # @api private
5
+ # Provides the implementation for `be_an_instance_of`.
6
+ # Not intended to be instantiated directly.
4
7
  class BeAnInstanceOf < BaseMatcher
5
- def match(expected, actual)
6
- actual.instance_of? expected
7
- end
8
-
8
+ # @api private
9
+ # @return [String]
9
10
  def description
10
11
  "be an instance of #{expected}"
11
12
  end
13
+
14
+ private
15
+
16
+ def match(expected, actual)
17
+ actual.instance_of?(expected)
18
+ rescue NoMethodError
19
+ raise ::ArgumentError, "The #{matcher_name} matcher requires that " \
20
+ "the actual object responds to #instance_of? method " \
21
+ "but a `NoMethodError` was encountered instead."
22
+ end
12
23
  end
13
24
  end
14
25
  end
@@ -1,9 +1,18 @@
1
1
  module RSpec
2
2
  module Matchers
3
3
  module BuiltIn
4
+ # @api private
5
+ # Provides the implementation for `be_a_kind_of`.
6
+ # Not intended to be instantiated directly.
4
7
  class BeAKindOf < BaseMatcher
8
+ private
9
+
5
10
  def match(expected, actual)
6
- actual.kind_of? expected
11
+ actual.kind_of?(expected)
12
+ rescue NoMethodError
13
+ raise ::ArgumentError, "The #{matcher_name} matcher requires that " \
14
+ "the actual object responds to #kind_of? method " \
15
+ "but a `NoMethodError` was encountered instead."
7
16
  end
8
17
  end
9
18
  end