rspec-expectations 3.12.3 → 3.13.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/Changelog.md +189 -132
- data/README.md +10 -4
- data/lib/rspec/expectations/block_snippet_extractor.rb +2 -0
- data/lib/rspec/expectations/configuration.rb +28 -14
- data/lib/rspec/expectations/fail_with.rb +1 -1
- data/lib/rspec/expectations/failure_aggregator.rb +7 -0
- data/lib/rspec/expectations/handler.rb +4 -5
- data/lib/rspec/expectations/version.rb +1 -1
- data/lib/rspec/matchers/built_in/base_matcher.rb +45 -18
- data/lib/rspec/matchers/built_in/change.rb +2 -0
- data/lib/rspec/matchers/built_in/compound.rb +6 -3
- data/lib/rspec/matchers/built_in/contain_exactly.rb +2 -0
- data/lib/rspec/matchers/built_in/count_expectation.rb +2 -0
- data/lib/rspec/matchers/built_in/eq.rb +5 -1
- data/lib/rspec/matchers/built_in/eql.rb +5 -1
- data/lib/rspec/matchers/built_in/has.rb +29 -2
- data/lib/rspec/matchers/built_in/include.rb +5 -0
- data/lib/rspec/matchers/built_in/match.rb +14 -0
- data/lib/rspec/matchers/built_in/raise_error.rb +5 -1
- data/lib/rspec/matchers/built_in/satisfy.rb +2 -0
- data/lib/rspec/matchers/dsl.rb +6 -5
- data/lib/rspec/matchers/english_phrasing.rb +2 -0
- data/lib/rspec/matchers/matcher_delegator.rb +27 -1
- data/lib/rspec/matchers/{expecteds_for_multiple_diffs.rb → multi_matcher_diff.rb} +16 -16
- data/lib/rspec/matchers.rb +3 -1
- data.tar.gz.sig +0 -0
- metadata +28 -87
- metadata.gz.sig +0 -0
data/README.md
CHANGED
@@ -13,7 +13,9 @@ If you want to use rspec-expectations with rspec, just install the rspec gem
|
|
13
13
|
and RubyGems will also install rspec-expectations for you (along with
|
14
14
|
rspec-core and rspec-mocks):
|
15
15
|
|
16
|
-
|
16
|
+
```shell
|
17
|
+
gem install rspec
|
18
|
+
```
|
17
19
|
|
18
20
|
Want to run against the `main` branch? You'll need to include the dependent
|
19
21
|
RSpec repos as well. Add the following to your `Gemfile`:
|
@@ -27,7 +29,9 @@ end
|
|
27
29
|
If you want to use rspec-expectations with another tool, like Test::Unit,
|
28
30
|
Minitest, or Cucumber, you can install it directly:
|
29
31
|
|
30
|
-
|
32
|
+
```shell
|
33
|
+
gem install rspec-expectations
|
34
|
+
```
|
31
35
|
|
32
36
|
## Contributing
|
33
37
|
|
@@ -67,8 +71,10 @@ The `describe` and `it` methods come from rspec-core. The `Order`, `LineItem`,
|
|
67
71
|
expresses an expected outcome. If `order.total == Money.new(5.55, :USD)`, then
|
68
72
|
the example passes. If not, it fails with a message like:
|
69
73
|
|
70
|
-
|
71
|
-
|
74
|
+
```
|
75
|
+
expected: #<Money @value=5.55 @currency=:USD>
|
76
|
+
got: #<Money @value=1.11 @currency=:USD>
|
77
|
+
```
|
72
78
|
|
73
79
|
## Built-in matchers
|
74
80
|
|
@@ -46,11 +46,13 @@ module RSpec
|
|
46
46
|
RSpec.world.source_from_file(file_path)
|
47
47
|
end
|
48
48
|
else
|
49
|
+
# :nocov:
|
49
50
|
RSpec::Support.require_rspec_support 'source'
|
50
51
|
def source
|
51
52
|
raise TargetNotFoundError unless File.exist?(file_path)
|
52
53
|
@source ||= RSpec::Support::Source.from_file(file_path)
|
53
54
|
end
|
55
|
+
# :nocov:
|
54
56
|
end
|
55
57
|
|
56
58
|
def file_path
|
@@ -89,6 +89,7 @@ module RSpec
|
|
89
89
|
::RSpec.configuration.color_enabled?
|
90
90
|
end
|
91
91
|
else
|
92
|
+
# :nocov:
|
92
93
|
# Indicates whether or not diffs should be colored.
|
93
94
|
# Delegates to rspec-core's color option if rspec-core
|
94
95
|
# is loaded; otherwise you can set it here.
|
@@ -100,8 +101,11 @@ module RSpec
|
|
100
101
|
def color?
|
101
102
|
defined?(@color) && @color
|
102
103
|
end
|
104
|
+
# :nocov:
|
103
105
|
end
|
104
106
|
|
107
|
+
# :nocov: Because this is only really _useful_ on 1.8, and hard to test elsewhere.
|
108
|
+
#
|
105
109
|
# Adds `should` and `should_not` to the given classes
|
106
110
|
# or modules. This can be used to ensure `should` works
|
107
111
|
# properly on things like proxy objects (particular
|
@@ -114,6 +118,7 @@ module RSpec
|
|
114
118
|
Expectations::Syntax.enable_should(mod)
|
115
119
|
end
|
116
120
|
end
|
121
|
+
# :nocov:
|
117
122
|
|
118
123
|
# Sets or gets the backtrace formatter. The backtrace formatter should
|
119
124
|
# implement `#format_backtrace(Array<String>)`. This is used
|
@@ -174,11 +179,18 @@ module RSpec
|
|
174
179
|
# no-op, handler is something else
|
175
180
|
end
|
176
181
|
end
|
182
|
+
|
183
|
+
# Configures what RSpec will do about matcher use which would potentially cause
|
184
|
+
# false positives in tests. Defaults to `:warn` since this is generally the desired behavior,
|
185
|
+
# but can also be set to `:raise` or `:nothing`.
|
177
186
|
#
|
178
|
-
#
|
179
|
-
#
|
180
|
-
#
|
181
|
-
#
|
187
|
+
# @overload on_potential_false_positives
|
188
|
+
# @return [Symbol] the behavior setting
|
189
|
+
# @overload on_potential_false_positives=(value)
|
190
|
+
# @param [Symbol] behavior can be set to `:warn`, `:raise` or `:nothing`
|
191
|
+
# @return [Symbol] the behavior setting
|
192
|
+
attr_reader :on_potential_false_positives
|
193
|
+
|
182
194
|
def on_potential_false_positives=(behavior)
|
183
195
|
unless FALSE_POSITIVE_BEHAVIOURS.key?(behavior)
|
184
196
|
raise ArgumentError, "Supported values are: #{FALSE_POSITIVE_BEHAVIOURS.keys}"
|
@@ -189,22 +201,24 @@ module RSpec
|
|
189
201
|
# Configures RSpec to check predicate matchers to `be(true)` / `be(false)` (strict),
|
190
202
|
# or `be_truthy` / `be_falsey` (not strict).
|
191
203
|
# Historically, the default was `false`, but `true` is recommended.
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
204
|
+
#
|
205
|
+
# @overload strict_predicate_matchers
|
206
|
+
# @return [Boolean]
|
207
|
+
# @overload strict_predicate_matchers?
|
208
|
+
# @return [Boolean]
|
209
|
+
# @overload strict_predicate_matchers=(value)
|
210
|
+
# @param [Boolean] value
|
197
211
|
attr_reader :strict_predicate_matchers
|
198
212
|
|
213
|
+
def strict_predicate_matchers=(value)
|
214
|
+
raise ArgumentError, "Pass `true` or `false`" unless value == true || value == false
|
215
|
+
@strict_predicate_matchers = value
|
216
|
+
end
|
217
|
+
|
199
218
|
def strict_predicate_matchers?
|
200
219
|
@strict_predicate_matchers
|
201
220
|
end
|
202
221
|
|
203
|
-
# Indicates what RSpec will do about matcher use which will
|
204
|
-
# potentially cause false positives in tests, generally you want to
|
205
|
-
# avoid such scenarios so this defaults to `true`.
|
206
|
-
attr_reader :on_potential_false_positives
|
207
|
-
|
208
222
|
# Indicates whether RSpec will warn about matcher use which will
|
209
223
|
# potentially cause false positives in tests, generally you want to
|
210
224
|
# avoid such scenarios so this defaults to `true`.
|
@@ -30,7 +30,7 @@ module RSpec
|
|
30
30
|
"appropriate failure_message[_when_negated] method to return a string?"
|
31
31
|
end
|
32
32
|
|
33
|
-
message = ::RSpec::Matchers::
|
33
|
+
message = ::RSpec::Matchers::MultiMatcherDiff.from(expected, actual).message_with_diff(message, differ)
|
34
34
|
|
35
35
|
RSpec::Support.notify_failure(RSpec::Expectations::ExpectationNotMetError.new message)
|
36
36
|
end
|
@@ -6,6 +6,10 @@ module RSpec
|
|
6
6
|
|
7
7
|
# @private
|
8
8
|
class AggregatedFailure
|
9
|
+
# :nocov:
|
10
|
+
# `inspect` was apparently used by some versions early in ruby 3 while constructing
|
11
|
+
# NoMethodError, but seems to be no longer.
|
12
|
+
#
|
9
13
|
# @private
|
10
14
|
MESSAGE =
|
11
15
|
'AggregatedFailure: This method caused a failure which has been ' \
|
@@ -15,6 +19,7 @@ module RSpec
|
|
15
19
|
def inspect
|
16
20
|
MESSAGE
|
17
21
|
end
|
22
|
+
# :nocov:
|
18
23
|
end
|
19
24
|
|
20
25
|
AGGREGATED_FAILURE = AggregatedFailure.new
|
@@ -75,11 +80,13 @@ module RSpec
|
|
75
80
|
# a backtrace that has a continuous common section with the raised `MultipleExpectationsNotMetError`,
|
76
81
|
# so that rspec-core's truncation logic can work properly on it to list the backtrace
|
77
82
|
# relative to the `aggregate_failures` block.
|
83
|
+
# :nocov:
|
78
84
|
def assign_backtrace(failure)
|
79
85
|
raise failure
|
80
86
|
rescue failure.class => e
|
81
87
|
failure.set_backtrace(e.backtrace)
|
82
88
|
end
|
89
|
+
# :nocov:
|
83
90
|
else
|
84
91
|
# Using `caller` performs better (and is simpler) than `raise` on most Rubies.
|
85
92
|
def assign_backtrace(failure)
|
@@ -4,11 +4,10 @@ module RSpec
|
|
4
4
|
module ExpectationHelper
|
5
5
|
def self.check_message(msg)
|
6
6
|
unless msg.nil? || msg.respond_to?(:to_str) || msg.respond_to?(:call)
|
7
|
-
|
8
|
-
"
|
9
|
-
msg.inspect
|
10
|
-
|
11
|
-
].join
|
7
|
+
RSpec.warning(
|
8
|
+
"ignoring the provided expectation message argument" \
|
9
|
+
"(#{ msg.inspect }) since it is not a string or a proc"
|
10
|
+
)
|
12
11
|
end
|
13
12
|
end
|
14
13
|
|
@@ -124,24 +124,6 @@ module RSpec
|
|
124
124
|
end
|
125
125
|
private_class_method :underscore
|
126
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
127
|
# @private
|
146
128
|
module HashFormatting
|
147
129
|
# `{ :a => 5, :b => 2 }.inspect` produces:
|
@@ -161,6 +143,51 @@ module RSpec
|
|
161
143
|
|
162
144
|
include HashFormatting
|
163
145
|
|
146
|
+
# @private
|
147
|
+
module StringEncodingFormatting
|
148
|
+
# @api private
|
149
|
+
# @return [Boolean] True if the actual and expected string encoding are different.
|
150
|
+
# i.e. the failure may be related to encoding differences and the encoding
|
151
|
+
# should be shown to the user. false otherwise.
|
152
|
+
if String.method_defined?(:encoding)
|
153
|
+
def string_encoding_differs?
|
154
|
+
actual.is_a?(String) && expected.is_a?(String) && actual.encoding != expected.encoding
|
155
|
+
end
|
156
|
+
else
|
157
|
+
# @api private
|
158
|
+
# @return [Boolean] False always as the curent Ruby version does not support String encoding
|
159
|
+
# :nocov:
|
160
|
+
def string_encoding_differs?
|
161
|
+
false
|
162
|
+
end
|
163
|
+
# :nocov:
|
164
|
+
end
|
165
|
+
module_function :string_encoding_differs?
|
166
|
+
|
167
|
+
if String.method_defined?(:encoding)
|
168
|
+
# @api private
|
169
|
+
# Formats a String's encoding as a human readable string
|
170
|
+
# @param value [String]
|
171
|
+
# @return [String]
|
172
|
+
def format_encoding(value)
|
173
|
+
"#<Encoding:#{value.encoding.name}>"
|
174
|
+
end
|
175
|
+
else
|
176
|
+
# @api private
|
177
|
+
# Formats a String's encoding as a human readable string
|
178
|
+
# @param _value [String]
|
179
|
+
# @return [nil] nil as the curent Ruby version does not support String encoding
|
180
|
+
# :nocov:
|
181
|
+
def format_encoding(_value)
|
182
|
+
nil
|
183
|
+
end
|
184
|
+
# :nocov:
|
185
|
+
end
|
186
|
+
module_function :format_encoding
|
187
|
+
end
|
188
|
+
|
189
|
+
include StringEncodingFormatting
|
190
|
+
|
164
191
|
# @api private
|
165
192
|
# Provides default implementations of failure messages, based on the `description`.
|
166
193
|
module DefaultFailureMessages
|
@@ -51,10 +51,10 @@ module RSpec
|
|
51
51
|
end
|
52
52
|
|
53
53
|
# @api private
|
54
|
-
# @return [RSpec::Matchers::
|
54
|
+
# @return [RSpec::Matchers::MultiMatcherDiff]
|
55
55
|
def expected
|
56
56
|
return nil unless evaluator
|
57
|
-
::RSpec::Matchers::
|
57
|
+
::RSpec::Matchers::MultiMatcherDiff.for_many_matchers(diffable_matcher_list)
|
58
58
|
end
|
59
59
|
|
60
60
|
protected
|
@@ -77,8 +77,11 @@ module RSpec
|
|
77
77
|
def match(_expected, actual)
|
78
78
|
evaluator_klass = if supports_block_expectations? && Proc === actual
|
79
79
|
NestedEvaluator
|
80
|
-
|
80
|
+
elsif supports_value_expectations?
|
81
81
|
SequentialEvaluator
|
82
|
+
else
|
83
|
+
# Can't raise an ArgumentError in this context, as it's rescued
|
84
|
+
raise "Block and value matchers can't be combined in a compound expectation (#{matcher_1.description}, #{matcher_2.description})"
|
82
85
|
end
|
83
86
|
|
84
87
|
@evaluator = evaluator_klass.new(actual, matcher_1, matcher_2)
|
@@ -108,12 +108,14 @@ module RSpec
|
|
108
108
|
end
|
109
109
|
|
110
110
|
if RUBY_VERSION == "1.8.7"
|
111
|
+
# :nocov:
|
111
112
|
def to_a_disallowed?(object)
|
112
113
|
case object
|
113
114
|
when NilClass, String then true
|
114
115
|
else Kernel == RSpec::Support.method_handle_for(object, :to_a).owner
|
115
116
|
end
|
116
117
|
end
|
118
|
+
# :nocov:
|
117
119
|
else
|
118
120
|
def to_a_disallowed?(object)
|
119
121
|
NilClass === object
|
@@ -8,7 +8,11 @@ module RSpec
|
|
8
8
|
# @api private
|
9
9
|
# @return [String]
|
10
10
|
def failure_message
|
11
|
-
|
11
|
+
if string_encoding_differs?
|
12
|
+
"\nexpected: #{format_encoding(expected)} #{expected_formatted}\n got: #{format_encoding(actual)} #{actual_formatted}\n\n(compared using ==)\n"
|
13
|
+
else
|
14
|
+
"\nexpected: #{expected_formatted}\n got: #{actual_formatted}\n\n(compared using ==)\n"
|
15
|
+
end
|
12
16
|
end
|
13
17
|
|
14
18
|
# @api private
|
@@ -8,7 +8,11 @@ module RSpec
|
|
8
8
|
# @api private
|
9
9
|
# @return [String]
|
10
10
|
def failure_message
|
11
|
-
|
11
|
+
if string_encoding_differs?
|
12
|
+
"\nexpected: #{format_encoding(expected)} #{expected_formatted}\n got: #{format_encoding(actual)} #{actual_formatted}\n\n(compared using eql?)\n"
|
13
|
+
else
|
14
|
+
"\nexpected: #{expected_formatted}\n got: #{actual_formatted}\n\n(compared using eql?)\n"
|
15
|
+
end
|
12
16
|
end
|
13
17
|
|
14
18
|
# @api private
|
@@ -46,8 +46,27 @@ module RSpec
|
|
46
46
|
|
47
47
|
private
|
48
48
|
|
49
|
+
# Catch a semi-frequent typo - if you have strict_predicate_matchers disabled and
|
50
|
+
# expect(spy).to have_receieveddd(:foo) it would be evergreen - the dynamic matcher
|
51
|
+
# queries `has_receiveddd?`, the spy _fakes_ the method, returning its (truthy) self.
|
52
|
+
if defined?(RSpec::Mocks::Double)
|
53
|
+
def really_responds_to?(method)
|
54
|
+
if RSpec::Mocks::Double === @actual
|
55
|
+
@actual.respond_to?(method) && methods_include?(method)
|
56
|
+
else
|
57
|
+
@actual.respond_to?(method)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
else
|
61
|
+
# :nocov:
|
62
|
+
def really_responds_to?(method)
|
63
|
+
@actual.respond_to?(method)
|
64
|
+
end
|
65
|
+
# :nocov:
|
66
|
+
end
|
67
|
+
|
49
68
|
def predicate_accessible?
|
50
|
-
|
69
|
+
really_responds_to?(predicate)
|
51
70
|
end
|
52
71
|
|
53
72
|
# support 1.8.7, evaluate once at load time for performance
|
@@ -56,11 +75,19 @@ module RSpec
|
|
56
75
|
def private_predicate?
|
57
76
|
@actual.private_methods.include? predicate.to_s
|
58
77
|
end
|
78
|
+
|
79
|
+
def methods_include?(method)
|
80
|
+
@actual.methods.include?(method.to_s)
|
81
|
+
end
|
59
82
|
# :nocov:
|
60
83
|
else
|
61
84
|
def private_predicate?
|
62
85
|
@actual.private_methods.include? predicate
|
63
86
|
end
|
87
|
+
|
88
|
+
def methods_include?(method)
|
89
|
+
@actual.methods.include?(method)
|
90
|
+
end
|
64
91
|
end
|
65
92
|
|
66
93
|
def predicate_result
|
@@ -155,7 +182,7 @@ module RSpec
|
|
155
182
|
end
|
156
183
|
|
157
184
|
def predicate_accessible?
|
158
|
-
super ||
|
185
|
+
super || really_responds_to?(present_tense_predicate)
|
159
186
|
end
|
160
187
|
|
161
188
|
def present_tense_predicate
|
@@ -13,6 +13,7 @@ module RSpec
|
|
13
13
|
|
14
14
|
# @api private
|
15
15
|
def initialize(*expecteds)
|
16
|
+
raise(ArgumentError, 'include() is not supported, please supply an argument') if expecteds.empty?
|
16
17
|
@expecteds = expecteds
|
17
18
|
end
|
18
19
|
|
@@ -165,6 +166,7 @@ module RSpec
|
|
165
166
|
end
|
166
167
|
|
167
168
|
def actual_collection_includes?(expected_item)
|
169
|
+
return actual.scan(expected_item).size > 0 if Regexp === expected_item && String === actual
|
168
170
|
return true if actual.include?(expected_item)
|
169
171
|
|
170
172
|
# String lacks an `any?` method...
|
@@ -174,9 +176,11 @@ module RSpec
|
|
174
176
|
end
|
175
177
|
|
176
178
|
if RUBY_VERSION < '1.9'
|
179
|
+
# :nocov:
|
177
180
|
def count_enumerable(expected_item)
|
178
181
|
actual.select { |value| values_match?(expected_item, value) }.size
|
179
182
|
end
|
183
|
+
# :nocov:
|
180
184
|
else
|
181
185
|
def count_enumerable(expected_item)
|
182
186
|
actual.count { |value| values_match?(expected_item, value) }
|
@@ -197,6 +201,7 @@ module RSpec
|
|
197
201
|
|
198
202
|
def diff_would_wrongly_highlight_matched_item?
|
199
203
|
return false unless actual.is_a?(String) && expected.is_a?(Array)
|
204
|
+
return false if Regexp === expecteds.first
|
200
205
|
|
201
206
|
lines = actual.split("\n")
|
202
207
|
expected.any? do |str|
|
@@ -33,11 +33,23 @@ module RSpec
|
|
33
33
|
self
|
34
34
|
end
|
35
35
|
|
36
|
+
# @api private
|
37
|
+
# @return [String]
|
38
|
+
def failure_message
|
39
|
+
if Array === expected && !(actual.respond_to?(:to_a) || actual.respond_to?(:to_ary))
|
40
|
+
return "expected a collection that can be converted to an array with " \
|
41
|
+
"`#to_ary` or `#to_a`, but got #{actual_formatted}"
|
42
|
+
end
|
43
|
+
|
44
|
+
super
|
45
|
+
end
|
46
|
+
|
36
47
|
private
|
37
48
|
|
38
49
|
def match(expected, actual)
|
39
50
|
return match_captures(expected, actual) if @expected_captures
|
40
51
|
return true if values_match?(expected, actual)
|
52
|
+
return false if Array === expected
|
41
53
|
return false unless can_safely_call_match?(expected, actual)
|
42
54
|
actual.match(expected)
|
43
55
|
end
|
@@ -78,9 +90,11 @@ module RSpec
|
|
78
90
|
# @api private
|
79
91
|
# Returns match data names for named captures
|
80
92
|
# @return Array
|
93
|
+
# :nocov:
|
81
94
|
def names
|
82
95
|
[]
|
83
96
|
end
|
97
|
+
# :nocov:
|
84
98
|
else
|
85
99
|
# @api private
|
86
100
|
# Returns match data names for named captures
|
@@ -13,6 +13,10 @@ module RSpec
|
|
13
13
|
# argument. We can't use `nil` for that because we need to warn when `nil` is
|
14
14
|
# passed in a different way. It's an Object, not a Module, since Module's `===`
|
15
15
|
# does not evaluate to true when compared to itself.
|
16
|
+
#
|
17
|
+
# Note; this _is_ the default value supplied for expected_error_or_message, but
|
18
|
+
# because there are two method-calls involved, that default is actually supplied
|
19
|
+
# in the definition of the _matcher_ method, `RSpec::Matchers#raise_error`
|
16
20
|
UndefinedValue = Object.new.freeze
|
17
21
|
|
18
22
|
def initialize(expected_error_or_message, expected_message, &block)
|
@@ -25,7 +29,7 @@ module RSpec
|
|
25
29
|
when nil, UndefinedValue
|
26
30
|
@expected_error = Exception
|
27
31
|
@expected_message = expected_message
|
28
|
-
when String
|
32
|
+
when String, Regexp
|
29
33
|
@expected_error = Exception
|
30
34
|
@expected_message = expected_error_or_message
|
31
35
|
else
|
data/lib/rspec/matchers/dsl.rb
CHANGED
@@ -467,11 +467,12 @@ module RSpec
|
|
467
467
|
@chained_method_clauses = []
|
468
468
|
@block_arg = block_arg
|
469
469
|
|
470
|
-
klass =
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
470
|
+
klass =
|
471
|
+
class << self
|
472
|
+
# See `Macros#define_user_override` above, for an explanation.
|
473
|
+
include(@user_method_defs = Module.new)
|
474
|
+
self
|
475
|
+
end
|
475
476
|
RSpec::Support::WithKeywordsWhenNeeded.class_exec(klass, *expected, &declarations)
|
476
477
|
end
|
477
478
|
|
@@ -45,12 +45,14 @@ module RSpec
|
|
45
45
|
# So here we replace `Kernel#Array` with our own warning-free implementation for 1.8.7.
|
46
46
|
# @private
|
47
47
|
# rubocop:disable Naming/MethodName
|
48
|
+
# :nocov:
|
48
49
|
def self.Array(obj)
|
49
50
|
case obj
|
50
51
|
when Array then obj
|
51
52
|
else [obj]
|
52
53
|
end
|
53
54
|
end
|
55
|
+
# :nocov:
|
54
56
|
# rubocop:enable Naming/MethodName
|
55
57
|
end
|
56
58
|
end
|
@@ -1,8 +1,34 @@
|
|
1
1
|
module RSpec
|
2
2
|
module Matchers
|
3
|
+
# Provides a base class with as little methods as possible, so that
|
4
|
+
# most methods can be delegated via `method_missing`.
|
5
|
+
#
|
6
|
+
# On Ruby 2.0+ BasicObject could be used for this purpose, but it
|
7
|
+
# introduce some extra complexity with constant resolution, so the
|
8
|
+
# BlankSlate pattern was prefered.
|
9
|
+
# @private
|
10
|
+
class BaseDelegator
|
11
|
+
kept_methods = [
|
12
|
+
# Methods that raise warnings if removed.
|
13
|
+
:__id__, :__send__, :object_id,
|
14
|
+
|
15
|
+
# Methods that are explicitly undefined in some subclasses.
|
16
|
+
:==, :===,
|
17
|
+
|
18
|
+
# Methods we keep on purpose.
|
19
|
+
:class, :respond_to?, :__method__, :method, :dup,
|
20
|
+
:clone, :initialize_dup, :initialize_copy, :initialize_clone,
|
21
|
+
]
|
22
|
+
instance_methods.each do |method|
|
23
|
+
unless kept_methods.include?(method.to_sym)
|
24
|
+
undef_method(method)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
3
29
|
# Provides the necessary plumbing to wrap a matcher with a decorator.
|
4
30
|
# @private
|
5
|
-
class MatcherDelegator
|
31
|
+
class MatcherDelegator < BaseDelegator
|
6
32
|
include Composable
|
7
33
|
attr_reader :base_matcher
|
8
34
|
|