From 27409f4a92c2ba3f1b4541b0f3e6054ca4873ac2 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Tue, 5 Mar 2019 13:52:59 -0700 Subject: [PATCH] Display last item and full list when #last is used Only perform one check with #responds_to?. --- src/spectator/matchers/end_with_matcher.cr | 62 ++++++++++++++++------ 1 file changed, 46 insertions(+), 16 deletions(-) diff --git a/src/spectator/matchers/end_with_matcher.cr b/src/spectator/matchers/end_with_matcher.cr index 96c0add..d4130f8 100644 --- a/src/spectator/matchers/end_with_matcher.cr +++ b/src/spectator/matchers/end_with_matcher.cr @@ -6,23 +6,31 @@ module Spectator::Matchers # Otherwise, it is treated as an `Indexable` and the `last` value is compared against. struct EndWithMatcher(ExpectedType) < ValueMatcher(ExpectedType) # Determines whether the matcher is satisfied with the value given to it. - private def match?(actual) - if actual.responds_to?(:ends_with?) - actual.ends_with?(expected) - else - expected === actual.last - end + private def match_ends_with?(actual) + actual.ends_with?(expected) + end + + # Determines whether the matcher is satisfied with the value given to it. + private def match_last?(actual) + expected === actual end # Determines whether the matcher is satisfied with the partial given to it. # `MatchData` is returned that contains information about the match. def match(partial) values = ExpectedActual.new(partial, self) - MatchData.new(match?(values.actual), values) + actual = values.actual + if actual.responds_to?(:ends_with?) + EndsWithMatchData.new(match_ends_with?(actual), values) + else + last = actual.last + LastMatchData.new(match_last?(last), values, last) + end end # Match data specific to this matcher. - private struct MatchData(ExpectedType, ActualType) < MatchData + # This type is used when the actual value responds to `ends_with?`. + private struct EndsWithMatchData(ExpectedType, ActualType) < MatchData # Creates the match data. def initialize(matched, @values : ExpectedActual(ExpectedType, ActualType)) super(matched) @@ -39,21 +47,43 @@ module Spectator::Matchers # 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 #{comparison_method})" + "#{@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 #{comparison_method})" + "#{@values.actual_label} does not end with #{@values.expected_label} (using #ends_with?)" + end + end + + # Match data specific to this matcher. + # This type is used when the actual value does not respond to `ends_with?`. + private struct LastMatchData(ExpectedType, ActualType, LastType) < MatchData + # Creates the match data. + def initialize(matched, @values : ExpectedActual(ExpectedType, ActualType), @last : LastType) + super(matched) end - private def comparison_method - if @values.actual.responds_to?(:ends_with?) - "#ends_with?" - else - "expected === actual.last" - end + # Information about the match. + def values + { + expected: @values.expected, + actual: @last, + list: @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 expected === actual.last)" + 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 expected === actual.last)" end end end