Created
July 29, 2015 15:26
-
-
Save jasonkarns/0b4c9483d11be82bae56 to your computer and use it in GitHub Desktop.
Custom Matcher that extends RSpec::Matchers::BuiltIn::Match to also enable specifying capture groups.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module CustomMatchers | |
class Match < RSpec::Matchers::BuiltIn::Match | |
def matches?(actual) | |
# first ensure the regex matched | |
return false unless result = super | |
# only continue if specifying captures | |
return result unless expected_captures = @captures | |
actual_captures = to_hash result | |
RSpec::Matchers::BuiltIn::Include.new(expected_captures).matches?(actual_captures).tap do |captures_matched| | |
# replace expected/actual regex with the matchdata | |
# if the matchdata didn't match. this way we get a diff of the matchdata hashes | |
# otherwise, leave untouched so the description is per normal | |
unless captures_matched | |
@expected = expected_captures | |
@actual = actual_captures | |
end | |
end | |
end | |
def capturing(captures) | |
@captures = captures | |
self | |
end | |
private | |
def to_hash(matchdata) | |
Hash[matchdata.names.map(&:to_sym).zip matchdata.captures] | |
end | |
end | |
def matchy(expected) | |
Match.new expected | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This custom matcher inherits from
RSpec::Matchers::BuiltIn::Match
and adds the methodcapturing
that enables specifying expected capture groups from the regex.It works be first invoking the normal
matches?
behavior with super. If that fails, it exits early with the normalMatch
error messaging. Then it checks if there are any specified captures; if not it exits early.If the match succeeded and there are capture expectations, then we convert the actual captures from a
MatchData
into a hash by zipping the capture group names and the capture values. (This initial attempt assumes named captures and does not support verifying indexed captures.)Then we leverage RSpec's built-in
Include
matcher to see if the actual captures match the expected captures. If it does match, then we're done and RSpec can emit the description based on the regex/string.If the captures do not match, then we know that RSpec will be emitting an error description based on the
@actual
and@expected
ivars. Since the actual regex has already been proven to match, the error description would be more useful if it show the expected/actual captures instead of the regex and string. So we overwrite the actual/expected ivars with the captures.