1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
|
module RSpec
module Matchers
module BuiltIn
# @api private
# Provides the implementation for dynamic predicate matchers.
# Not intended to be inherited directly.
class DynamicPredicate < BaseMatcher
include BeHelpers
def initialize(method_name, *args, &block)
@method_name, @args, @block = method_name, args, block
end
ruby2_keywords :initialize if respond_to?(:ruby2_keywords, true)
# @private
def matches?(actual, &block)
@actual = actual
@block ||= block
predicate_accessible? && predicate_matches?
end
# @private
def does_not_match?(actual, &block)
@actual = actual
@block ||= block
predicate_accessible? && predicate_matches?(false)
end
# @api private
# @return [String]
def failure_message
failure_message_expecting(true)
end
# @api private
# @return [String]
def failure_message_when_negated
failure_message_expecting(false)
end
# @api private
# @return [String]
def description
"#{method_description}#{args_to_sentence}"
end
private
def predicate_accessible?
@actual.respond_to? predicate
end
# support 1.8.7, evaluate once at load time for performance
if String === methods.first
# :nocov:
def private_predicate?
@actual.private_methods.include? predicate.to_s
end
# :nocov:
else
def private_predicate?
@actual.private_methods.include? predicate
end
end
def predicate_result
@predicate_result = actual.__send__(predicate_method_name, *@args, &@block)
end
def predicate_method_name
predicate
end
def predicate_matches?(value=true)
if RSpec::Expectations.configuration.strict_predicate_matchers?
value == predicate_result
else
value == !!predicate_result
end
end
def root
# On 1.9, there appears to be a bug where String#match can return `false`
# rather than the match data object. Changing to Regex#match appears to
# work around this bug. For an example of this bug, see:
# https://travis-ci.org/rspec/rspec-expectations/jobs/27549635
self.class::REGEX.match(@method_name.to_s).captures.first
end
def method_description
EnglishPhrasing.split_words(@method_name)
end
def failure_message_expecting(value)
validity_message ||
"expected `#{actual_formatted}.#{predicate}#{args_to_s}` to #{expectation_of value}, got #{description_of @predicate_result}"
end
def expectation_of(value)
if RSpec::Expectations.configuration.strict_predicate_matchers?
"return #{value}"
elsif value
"be truthy"
else
"be falsey"
end
end
def validity_message
return nil if predicate_accessible?
"expected #{actual_formatted} to respond to `#{predicate}`#{failure_to_respond_explanation}"
end
def failure_to_respond_explanation
if private_predicate?
" but `#{predicate}` is a private method"
end
end
end
# @api private
# Provides the implementation for `has_<predicate>`.
# Not intended to be instantiated directly.
class Has < DynamicPredicate
# :nodoc:
REGEX = Matchers::HAS_REGEX
private
def predicate
@predicate ||= :"has_#{root}?"
end
end
# @api private
# Provides the implementation of `be_<predicate>`.
# Not intended to be instantiated directly.
class BePredicate < DynamicPredicate
# :nodoc:
REGEX = Matchers::BE_PREDICATE_REGEX
private
def predicate
@predicate ||= :"#{root}?"
end
def predicate_method_name
actual.respond_to?(predicate) ? predicate : present_tense_predicate
end
def failure_to_respond_explanation
super || if predicate == :true?
" or perhaps you meant `be true` or `be_truthy`"
elsif predicate == :false?
" or perhaps you meant `be false` or `be_falsey`"
end
end
def predicate_accessible?
super || actual.respond_to?(present_tense_predicate)
end
def present_tense_predicate
:"#{root}s?"
end
end
end
end
end
|