Refactor EndWithMatcher

This commit is contained in:
Michael Miller 2019-08-07 00:08:32 -06:00
parent f2f46418a3
commit 72e5735106

View file

@ -1,88 +1,86 @@
require "./value_matcher" require "./failed_match_data"
require "./matcher"
require "./successful_match_data"
module Spectator::Matchers module Spectator::Matchers
# Matcher that tests whether a value, such as a `String` or `Array`, ends with a value. # Matcher that tests whether a value, such as a `String` or `Array`, ends with a value.
# The `ends_with?` method is used if it's defined on the actual type. # The `ends_with?` method is used if it's defined on the actual type.
# Otherwise, it is treated as an `Indexable` and the `last` value is compared against. # Otherwise, it is treated as an `Indexable` and the `last` value is compared against.
struct EndWithMatcher(ExpectedType) < ValueMatcher(ExpectedType) struct EndWithMatcher(ExpectedType) < Matcher
# Determines whether the matcher is satisfied with the value given to it. private getter expected
private def match_ends_with?(actual)
actual.ends_with?(expected) def initialize(@expected : TestValue(ExpectedType))
end end
# Determines whether the matcher is satisfied with the value given to it. def description
private def match_last?(actual) "ends with #{expected.label}"
expected === actual
end end
# Determines whether the matcher is satisfied with the partial given to it. def match(actual)
def match(partial, negated = false) if actual.value.responds_to?(:ends_with?)
values = ExpectedActual.new(partial, self) match_ends_with(actual)
actual = values.actual
if actual.responds_to?(:ends_with?)
EndsWithMatchData.new(match_ends_with?(actual), values)
else else
last = actual.last match_last(actual)
LastMatchData.new(match_last?(last), values, last)
end end
end end
# Match data specific to this matcher. private def match_ends_with(actual)
# This type is used when the actual value responds to `ends_with?`. if actual.value.ends_with?(expected.value)
private struct EndsWithMatchData(ExpectedType, ActualType) < MatchData SuccessfulMatchData.new
# Creates the match data. else
def initialize(matched, @values : ExpectedActual(ExpectedType, ActualType)) FailedMatchData.new("#{actual.label} does not end with #{expected.label} (using #ends_with?)",
super(matched) expected: expected.value.inspect,
end actual: actual.value.inspect
)
# Information about the match.
def named_tuple
{
expected: NegatableMatchDataValue.new(@values.expected),
actual: @values.actual,
}
end
# Describes the condition that satisfies the matcher.
# This is informational and displayed to the end-user.
def message
"#{@values.actual_label} ends with #{@values.expected_label} (using #ends_with?)"
end
# Describes the condition that won't satsify the matcher.
# This is informational and displayed to the end-user.
def negated_message
"#{@values.actual_label} does not end with #{@values.expected_label} (using #ends_with?)"
end end
end end
# Match data specific to this matcher. private def match_last(actual)
# This type is used when the actual value does not respond to `ends_with?`. list = actual.value.to_a
private struct LastMatchData(ExpectedType, ActualType, LastType) < MatchData last = list.last
# Creates the match data.
def initialize(matched, @values : ExpectedActual(ExpectedType, ActualType), @last : LastType)
super(matched)
end
# Information about the match. if expected.value === last
def named_tuple SuccessfulMatchData.new
{ else
expected: @values.expected, FailedMatchData.new("#{actual.label} does not end with #{expected.label} (using expected === last)",
actual: @last, expected: expected.value,
list: @values.actual, actual: last,
} list: list
)
end end
end
# Describes the condition that satisfies the matcher. def negated_match(actual)
# This is informational and displayed to the end-user. if actual.value.responds_to?(:ends_with?)
def message negated_match_ends_with(actual)
"#{@values.actual_label} ends with #{@values.expected_label} (using expected === actual.last)" else
negated_match_last(actual)
end end
end
# Describes the condition that won't satsify the matcher. private def negated_match_ends_with(actual)
# This is informational and displayed to the end-user. if actual.value.ends_with?(expected.value)
def negated_message FailedMatchData.new("#{actual.label} ends with #{expected.label} (using #ends_with?)",
"#{@values.actual_label} does not end with #{@values.expected_label} (using expected === actual.last)" expected: expected.value.inspect,
actual: actual.value.inspect
)
else
SuccessfulMatchData.new
end
end
private def negated_match_last(actual)
list = actual.value.to_a
last = list.last
if expected.value === last
FailedMatchData.new("#{actual.label} ends with #{expected.label} (using expected === last)",
expected: expected.value,
actual: last,
list: list
)
else
SuccessfulMatchData.new
end end
end end
end end