rspec-expectations 3.0.4 → 3.12.3
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 +5 -5
- checksums.yaml.gz.sig +0 -0
- data/.document +1 -1
- data/.yardopts +1 -1
- data/Changelog.md +530 -5
- data/{License.txt → LICENSE.md} +5 -4
- data/README.md +73 -31
- data/lib/rspec/expectations/block_snippet_extractor.rb +253 -0
- data/lib/rspec/expectations/configuration.rb +96 -1
- data/lib/rspec/expectations/expectation_target.rb +82 -38
- data/lib/rspec/expectations/fail_with.rb +11 -6
- data/lib/rspec/expectations/failure_aggregator.rb +229 -0
- data/lib/rspec/expectations/handler.rb +36 -15
- data/lib/rspec/expectations/minitest_integration.rb +43 -2
- data/lib/rspec/expectations/syntax.rb +5 -5
- data/lib/rspec/expectations/version.rb +1 -1
- data/lib/rspec/expectations.rb +15 -1
- data/lib/rspec/matchers/aliased_matcher.rb +79 -4
- data/lib/rspec/matchers/built_in/all.rb +11 -0
- data/lib/rspec/matchers/built_in/base_matcher.rb +111 -28
- data/lib/rspec/matchers/built_in/be.rb +28 -114
- data/lib/rspec/matchers/built_in/be_between.rb +1 -1
- data/lib/rspec/matchers/built_in/be_instance_of.rb +5 -1
- data/lib/rspec/matchers/built_in/be_kind_of.rb +5 -1
- data/lib/rspec/matchers/built_in/be_within.rb +5 -12
- data/lib/rspec/matchers/built_in/change.rb +171 -63
- data/lib/rspec/matchers/built_in/compound.rb +201 -30
- data/lib/rspec/matchers/built_in/contain_exactly.rb +73 -12
- data/lib/rspec/matchers/built_in/count_expectation.rb +169 -0
- data/lib/rspec/matchers/built_in/eq.rb +3 -38
- data/lib/rspec/matchers/built_in/eql.rb +2 -2
- data/lib/rspec/matchers/built_in/equal.rb +3 -3
- data/lib/rspec/matchers/built_in/exist.rb +7 -3
- data/lib/rspec/matchers/built_in/has.rb +93 -30
- data/lib/rspec/matchers/built_in/have_attributes.rb +114 -0
- data/lib/rspec/matchers/built_in/include.rb +133 -25
- data/lib/rspec/matchers/built_in/match.rb +79 -2
- data/lib/rspec/matchers/built_in/operators.rb +14 -5
- data/lib/rspec/matchers/built_in/output.rb +59 -2
- data/lib/rspec/matchers/built_in/raise_error.rb +130 -27
- data/lib/rspec/matchers/built_in/respond_to.rb +117 -15
- data/lib/rspec/matchers/built_in/satisfy.rb +28 -14
- data/lib/rspec/matchers/built_in/{start_and_end_with.rb → start_or_end_with.rb} +20 -8
- data/lib/rspec/matchers/built_in/throw_symbol.rb +15 -5
- data/lib/rspec/matchers/built_in/yield.rb +129 -156
- data/lib/rspec/matchers/built_in.rb +5 -3
- data/lib/rspec/matchers/composable.rb +24 -36
- data/lib/rspec/matchers/dsl.rb +203 -37
- data/lib/rspec/matchers/english_phrasing.rb +58 -0
- data/lib/rspec/matchers/expecteds_for_multiple_diffs.rb +82 -0
- data/lib/rspec/matchers/fail_matchers.rb +42 -0
- data/lib/rspec/matchers/generated_descriptions.rb +1 -2
- data/lib/rspec/matchers/matcher_delegator.rb +3 -4
- data/lib/rspec/matchers/matcher_protocol.rb +105 -0
- data/lib/rspec/matchers.rb +267 -144
- data.tar.gz.sig +0 -0
- metadata +71 -49
- metadata.gz.sig +0 -0
- data/lib/rspec/matchers/pretty.rb +0 -77
@@ -23,19 +23,94 @@ module RSpec
|
|
23
23
|
# used.
|
24
24
|
def method_missing(*)
|
25
25
|
return_val = super
|
26
|
-
return return_val unless
|
27
|
-
|
26
|
+
return return_val unless RSpec::Matchers.is_a_matcher?(return_val)
|
27
|
+
self.class.new(return_val, @description_block)
|
28
28
|
end
|
29
29
|
|
30
30
|
# Provides the description of the aliased matcher. Aliased matchers
|
31
31
|
# are designed to behave identically to the original matcher except
|
32
|
-
# for
|
33
|
-
# name.
|
32
|
+
# for the description and failure messages. The description is different
|
33
|
+
# to reflect the aliased name.
|
34
34
|
#
|
35
35
|
# @api private
|
36
36
|
def description
|
37
37
|
@description_block.call(super)
|
38
38
|
end
|
39
|
+
|
40
|
+
# Provides the failure_message of the aliased matcher. Aliased matchers
|
41
|
+
# are designed to behave identically to the original matcher except
|
42
|
+
# for the description and failure messages. The failure_message is different
|
43
|
+
# to reflect the aliased name.
|
44
|
+
#
|
45
|
+
# @api private
|
46
|
+
def failure_message
|
47
|
+
@description_block.call(super)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Provides the failure_message_when_negated of the aliased matcher. Aliased matchers
|
51
|
+
# are designed to behave identically to the original matcher except
|
52
|
+
# for the description and failure messages. The failure_message_when_negated is different
|
53
|
+
# to reflect the aliased name.
|
54
|
+
#
|
55
|
+
# @api private
|
56
|
+
def failure_message_when_negated
|
57
|
+
@description_block.call(super)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Decorator used for matchers that have special implementations of
|
62
|
+
# operators like `==` and `===`.
|
63
|
+
# @private
|
64
|
+
class AliasedMatcherWithOperatorSupport < AliasedMatcher
|
65
|
+
# We undef these so that they get delegated via `method_missing`.
|
66
|
+
undef ==
|
67
|
+
undef ===
|
68
|
+
end
|
69
|
+
|
70
|
+
# @private
|
71
|
+
class AliasedNegatedMatcher < AliasedMatcher
|
72
|
+
def matches?(*args, &block)
|
73
|
+
if @base_matcher.respond_to?(:does_not_match?)
|
74
|
+
@base_matcher.does_not_match?(*args, &block)
|
75
|
+
else
|
76
|
+
!super
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def does_not_match?(*args, &block)
|
81
|
+
@base_matcher.matches?(*args, &block)
|
82
|
+
end
|
83
|
+
|
84
|
+
def failure_message
|
85
|
+
optimal_failure_message(__method__, :failure_message_when_negated)
|
86
|
+
end
|
87
|
+
|
88
|
+
def failure_message_when_negated
|
89
|
+
optimal_failure_message(__method__, :failure_message)
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
DefaultFailureMessages = BuiltIn::BaseMatcher::DefaultFailureMessages
|
95
|
+
|
96
|
+
# For a matcher that uses the default failure messages, we prefer to
|
97
|
+
# use the override provided by the `description_block`, because it
|
98
|
+
# includes the phrasing that the user has expressed a preference for
|
99
|
+
# by going through the effort of defining a negated matcher.
|
100
|
+
#
|
101
|
+
# However, if the override didn't actually change anything, then we
|
102
|
+
# should return the opposite failure message instead -- the overridden
|
103
|
+
# message is going to be confusing if we return it as-is, as it represents
|
104
|
+
# the non-negated failure message for a negated match (or vice versa).
|
105
|
+
def optimal_failure_message(same, inverted)
|
106
|
+
if DefaultFailureMessages.has_default_failure_messages?(@base_matcher)
|
107
|
+
base_message = @base_matcher.__send__(same)
|
108
|
+
overridden = @description_block.call(base_message)
|
109
|
+
return overridden if overridden != base_message
|
110
|
+
end
|
111
|
+
|
112
|
+
@base_matcher.__send__(inverted)
|
113
|
+
end
|
39
114
|
end
|
40
115
|
end
|
41
116
|
end
|
@@ -21,6 +21,10 @@ module RSpec
|
|
21
21
|
# @api private
|
22
22
|
# @return [String]
|
23
23
|
def failure_message
|
24
|
+
unless iterable?
|
25
|
+
return "#{improve_hash_formatting(super)}, but was not iterable"
|
26
|
+
end
|
27
|
+
|
24
28
|
all_messages = [improve_hash_formatting(super)]
|
25
29
|
failed_objects.each do |index, matcher_failure_message|
|
26
30
|
all_messages << failure_message_for_item(index, matcher_failure_message)
|
@@ -37,6 +41,8 @@ module RSpec
|
|
37
41
|
private
|
38
42
|
|
39
43
|
def match(_expected, _actual)
|
44
|
+
return false unless iterable?
|
45
|
+
|
40
46
|
index_failed_objects
|
41
47
|
failed_objects.empty?
|
42
48
|
end
|
@@ -67,8 +73,13 @@ module RSpec
|
|
67
73
|
|
68
74
|
def initialize_copy(other)
|
69
75
|
@matcher = @matcher.clone
|
76
|
+
@failed_objects = @failed_objects.clone
|
70
77
|
super
|
71
78
|
end
|
79
|
+
|
80
|
+
def iterable?
|
81
|
+
@actual.respond_to?(:each_with_index)
|
82
|
+
end
|
72
83
|
end
|
73
84
|
end
|
74
85
|
end
|
@@ -8,11 +8,10 @@ module RSpec
|
|
8
8
|
#
|
9
9
|
# ### Warning:
|
10
10
|
#
|
11
|
-
# This class is for internal use, and subject to change without notice.
|
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
|
16
15
|
include RSpec::Matchers::Composable
|
17
16
|
|
18
17
|
# @api private
|
@@ -23,6 +22,9 @@ module RSpec
|
|
23
22
|
# @private
|
24
23
|
attr_reader :actual, :expected, :rescued_exception
|
25
24
|
|
25
|
+
# @private
|
26
|
+
attr_writer :matcher_name
|
27
|
+
|
26
28
|
def initialize(expected=UNDEFINED)
|
27
29
|
@expected = expected unless UNDEFINED.equal?(expected)
|
28
30
|
end
|
@@ -53,31 +55,12 @@ module RSpec
|
|
53
55
|
end
|
54
56
|
|
55
57
|
# @api private
|
56
|
-
#
|
57
|
-
# When subclassing, if you are not satisfied with this failure message
|
58
|
-
# you often only need to override `description`.
|
59
|
-
# @return [String]
|
60
|
-
def failure_message
|
61
|
-
assert_ivars :@actual
|
62
|
-
"expected #{@actual.inspect} to #{description}"
|
63
|
-
end
|
64
|
-
|
65
|
-
# @api private
|
66
|
-
# Provides a good generic negative failure message. Based on `description`.
|
67
|
-
# When subclassing, if you are not satisfied with this failure message
|
68
|
-
# you often only need to override `description`.
|
69
|
-
# @return [String]
|
70
|
-
def failure_message_when_negated
|
71
|
-
assert_ivars :@actual
|
72
|
-
"expected #{@actual.inspect} not to #{description}"
|
73
|
-
end
|
74
|
-
|
75
|
-
# @api private
|
76
|
-
# Generates a "pretty" description using the logic in {Pretty}.
|
58
|
+
# Generates a description using {EnglishPhrasing}.
|
77
59
|
# @return [String]
|
78
60
|
def description
|
79
|
-
|
80
|
-
|
61
|
+
desc = EnglishPhrasing.split_words(self.class.matcher_name)
|
62
|
+
desc << EnglishPhrasing.list(@expected) if defined?(@expected)
|
63
|
+
desc
|
81
64
|
end
|
82
65
|
|
83
66
|
# @api private
|
@@ -95,20 +78,120 @@ module RSpec
|
|
95
78
|
false
|
96
79
|
end
|
97
80
|
|
81
|
+
# @private
|
82
|
+
def supports_value_expectations?
|
83
|
+
true
|
84
|
+
end
|
85
|
+
|
86
|
+
# @api private
|
87
|
+
def expects_call_stack_jump?
|
88
|
+
false
|
89
|
+
end
|
90
|
+
|
91
|
+
# @private
|
92
|
+
def expected_formatted
|
93
|
+
RSpec::Support::ObjectFormatter.format(@expected)
|
94
|
+
end
|
95
|
+
|
96
|
+
# @private
|
97
|
+
def actual_formatted
|
98
|
+
RSpec::Support::ObjectFormatter.format(@actual)
|
99
|
+
end
|
100
|
+
|
101
|
+
# @private
|
102
|
+
def self.matcher_name
|
103
|
+
@matcher_name ||= underscore(name.split('::').last)
|
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
|
+
|
98
127
|
private
|
99
128
|
|
100
129
|
def assert_ivars(*expected_ivars)
|
101
130
|
return unless (expected_ivars - present_ivars).any?
|
102
|
-
|
131
|
+
ivar_list = EnglishPhrasing.list(expected_ivars)
|
132
|
+
raise "#{self.class.name} needs to supply#{ivar_list}"
|
103
133
|
end
|
104
134
|
|
105
135
|
if RUBY_VERSION.to_f < 1.9
|
136
|
+
# :nocov:
|
106
137
|
def present_ivars
|
107
|
-
instance_variables.map
|
138
|
+
instance_variables.map(&:to_sym)
|
108
139
|
end
|
140
|
+
# :nocov:
|
109
141
|
else
|
110
142
|
alias present_ivars instance_variables
|
111
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
|
+
# @api private
|
165
|
+
# Provides default implementations of failure messages, based on the `description`.
|
166
|
+
module DefaultFailureMessages
|
167
|
+
# @api private
|
168
|
+
# Provides a good generic failure message. Based on `description`.
|
169
|
+
# When subclassing, if you are not satisfied with this failure message
|
170
|
+
# you often only need to override `description`.
|
171
|
+
# @return [String]
|
172
|
+
def failure_message
|
173
|
+
"expected #{description_of @actual} to #{description}".dup
|
174
|
+
end
|
175
|
+
|
176
|
+
# @api private
|
177
|
+
# Provides a good generic negative failure message. Based on `description`.
|
178
|
+
# When subclassing, if you are not satisfied with this failure message
|
179
|
+
# you often only need to override `description`.
|
180
|
+
# @return [String]
|
181
|
+
def failure_message_when_negated
|
182
|
+
"expected #{description_of @actual} not to #{description}".dup
|
183
|
+
end
|
184
|
+
|
185
|
+
# @private
|
186
|
+
def self.has_default_failure_messages?(matcher)
|
187
|
+
matcher.method(:failure_message).owner == self &&
|
188
|
+
matcher.method(:failure_message_when_negated).owner == self
|
189
|
+
rescue NameError
|
190
|
+
false
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
include DefaultFailureMessages
|
112
195
|
end
|
113
196
|
end
|
114
197
|
end
|
@@ -8,13 +8,13 @@ module RSpec
|
|
8
8
|
# @api private
|
9
9
|
# @return [String]
|
10
10
|
def failure_message
|
11
|
-
"expected: truthy value\n got: #{
|
11
|
+
"expected: truthy value\n got: #{actual_formatted}"
|
12
12
|
end
|
13
13
|
|
14
14
|
# @api private
|
15
15
|
# @return [String]
|
16
16
|
def failure_message_when_negated
|
17
|
-
"expected: falsey value\n got: #{
|
17
|
+
"expected: falsey value\n got: #{actual_formatted}"
|
18
18
|
end
|
19
19
|
|
20
20
|
private
|
@@ -31,13 +31,13 @@ module RSpec
|
|
31
31
|
# @api private
|
32
32
|
# @return [String]
|
33
33
|
def failure_message
|
34
|
-
"expected: falsey value\n got: #{
|
34
|
+
"expected: falsey value\n got: #{actual_formatted}"
|
35
35
|
end
|
36
36
|
|
37
37
|
# @api private
|
38
38
|
# @return [String]
|
39
39
|
def failure_message_when_negated
|
40
|
-
"expected: truthy value\n got: #{
|
40
|
+
"expected: truthy value\n got: #{actual_formatted}"
|
41
41
|
end
|
42
42
|
|
43
43
|
private
|
@@ -54,7 +54,7 @@ module RSpec
|
|
54
54
|
# @api private
|
55
55
|
# @return [String]
|
56
56
|
def failure_message
|
57
|
-
"expected: nil\n got: #{
|
57
|
+
"expected: nil\n got: #{actual_formatted}"
|
58
58
|
end
|
59
59
|
|
60
60
|
# @api private
|
@@ -83,15 +83,15 @@ module RSpec
|
|
83
83
|
end
|
84
84
|
|
85
85
|
def inspected_args
|
86
|
-
@args.map { |a| a
|
86
|
+
@args.map { |a| RSpec::Support::ObjectFormatter.format(a) }
|
87
87
|
end
|
88
88
|
|
89
89
|
def expected_to_sentence
|
90
|
-
split_words(@expected)
|
90
|
+
EnglishPhrasing.split_words(@expected)
|
91
91
|
end
|
92
92
|
|
93
93
|
def args_to_sentence
|
94
|
-
|
94
|
+
EnglishPhrasing.list(@args)
|
95
95
|
end
|
96
96
|
end
|
97
97
|
|
@@ -108,13 +108,13 @@ module RSpec
|
|
108
108
|
# @api private
|
109
109
|
# @return [String]
|
110
110
|
def failure_message
|
111
|
-
"expected #{
|
111
|
+
"expected #{actual_formatted} to evaluate to true"
|
112
112
|
end
|
113
113
|
|
114
114
|
# @api private
|
115
115
|
# @return [String]
|
116
116
|
def failure_message_when_negated
|
117
|
-
"expected #{
|
117
|
+
"expected #{actual_formatted} to evaluate to false"
|
118
118
|
end
|
119
119
|
|
120
120
|
[:==, :<, :<=, :>=, :>, :===, :=~].each do |operator|
|
@@ -137,25 +137,35 @@ module RSpec
|
|
137
137
|
include BeHelpers
|
138
138
|
|
139
139
|
def initialize(operand, operator)
|
140
|
-
@expected
|
140
|
+
@expected = operand
|
141
|
+
@operator = operator
|
141
142
|
@args = []
|
142
143
|
end
|
143
144
|
|
144
145
|
def matches?(actual)
|
145
|
-
|
146
|
-
|
146
|
+
perform_match(actual)
|
147
|
+
rescue ArgumentError, NoMethodError
|
148
|
+
false
|
149
|
+
end
|
150
|
+
|
151
|
+
def does_not_match?(actual)
|
152
|
+
!perform_match(actual)
|
153
|
+
rescue ArgumentError, NoMethodError
|
154
|
+
false
|
147
155
|
end
|
148
156
|
|
149
157
|
# @api private
|
150
158
|
# @return [String]
|
151
159
|
def failure_message
|
152
|
-
"expected: #{@operator} #{
|
160
|
+
"expected: #{@operator} #{expected_formatted}\n" \
|
161
|
+
" got: #{@operator.to_s.gsub(/./, ' ')} #{actual_formatted}"
|
153
162
|
end
|
154
163
|
|
155
164
|
# @api private
|
156
165
|
# @return [String]
|
157
166
|
def failure_message_when_negated
|
158
|
-
message = "`expect(#{
|
167
|
+
message = "`expect(#{actual_formatted}).not_to " \
|
168
|
+
"be #{@operator} #{expected_formatted}`"
|
159
169
|
if [:<, :>, :<=, :>=].include?(@operator)
|
160
170
|
message + " not only FAILED, it is a bit confusing."
|
161
171
|
else
|
@@ -168,108 +178,12 @@ module RSpec
|
|
168
178
|
def description
|
169
179
|
"be #{@operator} #{expected_to_sentence}#{args_to_sentence}"
|
170
180
|
end
|
171
|
-
end
|
172
|
-
|
173
|
-
# @api private
|
174
|
-
# Provides the implementation of `be_<predicate>`.
|
175
|
-
# Not intended to be instantiated directly.
|
176
|
-
class BePredicate < BaseMatcher
|
177
|
-
include BeHelpers
|
178
|
-
|
179
|
-
def initialize(*args, &block)
|
180
|
-
@expected = parse_expected(args.shift)
|
181
|
-
@args = args
|
182
|
-
@block = block
|
183
|
-
end
|
184
|
-
|
185
|
-
def matches?(actual, &block)
|
186
|
-
@actual = actual
|
187
|
-
@block ||= block
|
188
|
-
predicate_accessible? && predicate_matches?
|
189
|
-
end
|
190
|
-
|
191
|
-
def does_not_match?(actual, &block)
|
192
|
-
@actual = actual
|
193
|
-
@block ||= block
|
194
|
-
predicate_accessible? && !predicate_matches?
|
195
|
-
end
|
196
|
-
|
197
|
-
# @api private
|
198
|
-
# @return [String]
|
199
|
-
def failure_message
|
200
|
-
failure_message_expecting(true)
|
201
|
-
end
|
202
|
-
|
203
|
-
# @api private
|
204
|
-
# @return [String]
|
205
|
-
def failure_message_when_negated
|
206
|
-
failure_message_expecting(false)
|
207
|
-
end
|
208
|
-
|
209
|
-
# @api private
|
210
|
-
# @return [String]
|
211
|
-
def description
|
212
|
-
"#{prefix_to_sentence}#{expected_to_sentence}#{args_to_sentence}"
|
213
|
-
end
|
214
181
|
|
215
182
|
private
|
216
183
|
|
217
|
-
def
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
# support 1.8.7, evaluate once at load time for performance
|
222
|
-
if String === methods.first
|
223
|
-
def private_predicate?
|
224
|
-
@actual.private_methods.include? predicate.to_s
|
225
|
-
end
|
226
|
-
else
|
227
|
-
def private_predicate?
|
228
|
-
@actual.private_methods.include? predicate
|
229
|
-
end
|
230
|
-
end
|
231
|
-
|
232
|
-
def predicate_exists?
|
233
|
-
actual.respond_to?(predicate) || actual.respond_to?(present_tense_predicate)
|
234
|
-
end
|
235
|
-
|
236
|
-
def predicate_matches?
|
237
|
-
method_name = actual.respond_to?(predicate) ? predicate : present_tense_predicate
|
238
|
-
@predicate_matches = actual.__send__(method_name, *@args, &@block)
|
239
|
-
end
|
240
|
-
|
241
|
-
def predicate
|
242
|
-
:"#{@expected}?"
|
243
|
-
end
|
244
|
-
|
245
|
-
def present_tense_predicate
|
246
|
-
:"#{@expected}s?"
|
247
|
-
end
|
248
|
-
|
249
|
-
def parse_expected(expected)
|
250
|
-
@prefix, expected = prefix_and_expected(expected)
|
251
|
-
expected
|
252
|
-
end
|
253
|
-
|
254
|
-
def prefix_and_expected(symbol)
|
255
|
-
Matchers::BE_PREDICATE_REGEX.match(symbol.to_s).captures.compact
|
256
|
-
end
|
257
|
-
|
258
|
-
def prefix_to_sentence
|
259
|
-
split_words(@prefix)
|
260
|
-
end
|
261
|
-
|
262
|
-
def failure_message_expecting(value)
|
263
|
-
validity_message ||
|
264
|
-
"expected `#{@actual.inspect}.#{predicate}#{args_to_s}` to return #{value}, got #{@predicate_matches.inspect}"
|
265
|
-
end
|
266
|
-
|
267
|
-
def validity_message
|
268
|
-
if private_predicate?
|
269
|
-
"expected #{@actual} to respond to `#{predicate}` but `#{predicate}` is a private method"
|
270
|
-
elsif !predicate_exists?
|
271
|
-
"expected #{@actual} to respond to `#{predicate}`"
|
272
|
-
end
|
184
|
+
def perform_match(actual)
|
185
|
+
@actual = actual
|
186
|
+
@actual.__send__ @operator, @expected
|
273
187
|
end
|
274
188
|
end
|
275
189
|
end
|
@@ -14,7 +14,11 @@ module RSpec
|
|
14
14
|
private
|
15
15
|
|
16
16
|
def match(expected, actual)
|
17
|
-
actual.instance_of?
|
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."
|
18
22
|
end
|
19
23
|
end
|
20
24
|
end
|
@@ -8,7 +8,11 @@ module RSpec
|
|
8
8
|
private
|
9
9
|
|
10
10
|
def match(expected, actual)
|
11
|
-
actual.kind_of?
|
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."
|
12
16
|
end
|
13
17
|
end
|
14
18
|
end
|
@@ -4,9 +4,7 @@ module RSpec
|
|
4
4
|
# @api private
|
5
5
|
# Provides the implementation for `be_within`.
|
6
6
|
# Not intended to be instantiated directly.
|
7
|
-
class BeWithin
|
8
|
-
include Composable
|
9
|
-
|
7
|
+
class BeWithin < BaseMatcher
|
10
8
|
def initialize(delta)
|
11
9
|
@delta = delta
|
12
10
|
end
|
@@ -25,7 +23,7 @@ module RSpec
|
|
25
23
|
# a percent comparison.
|
26
24
|
def percent_of(expected)
|
27
25
|
@expected = expected
|
28
|
-
@tolerance = @
|
26
|
+
@tolerance = @expected.abs * @delta / 100.0
|
29
27
|
@unit = '%'
|
30
28
|
self
|
31
29
|
end
|
@@ -40,24 +38,19 @@ module RSpec
|
|
40
38
|
# @api private
|
41
39
|
# @return [String]
|
42
40
|
def failure_message
|
43
|
-
"expected #{
|
41
|
+
"expected #{actual_formatted} to #{description}#{not_numeric_clause}"
|
44
42
|
end
|
45
43
|
|
46
44
|
# @api private
|
47
45
|
# @return [String]
|
48
46
|
def failure_message_when_negated
|
49
|
-
"expected #{
|
47
|
+
"expected #{actual_formatted} not to #{description}"
|
50
48
|
end
|
51
49
|
|
52
50
|
# @api private
|
53
51
|
# @return [String]
|
54
52
|
def description
|
55
|
-
"be within #{@delta}#{@unit} of #{
|
56
|
-
end
|
57
|
-
|
58
|
-
# @private
|
59
|
-
def supports_block_expectations?
|
60
|
-
false
|
53
|
+
"be within #{@delta}#{@unit} of #{expected_formatted}"
|
61
54
|
end
|
62
55
|
|
63
56
|
private
|