Credence.Pattern.PreferRegexMatch (credence v0.7.0)

Copy Markdown

Rewrites a case over Regex.run/2 that only tests whether the regex matched — never the captured groups — into the idiomatic boolean form built on Regex.match?/2.

Bad

case Regex.run(~r/ab{3,}/, string) do
  [_ | _] -> "Found a match!"
  _ -> "Not matched!"
end

Good

if Regex.match?(~r/ab{3,}/, string) do
  "Found a match!"
else
  "Not matched!"
end

Scope (the safe core)

Regex.run(re, str) (default :capture) returns nil on no match and a non-empty list (the whole match is always element 0) on a match. So the pattern [_ | _] matches exactly the "matched" case and nil/_ the "no match" case — which is precisely what Regex.match?/2 decides. The fix fires only when ALL of these hold:

  • The scrutinee is Regex.run(re, str) with exactly two arguments.
  • There are exactly two clauses, neither guarded.
  • One clause pattern is [_ | _] (wildcard head and tail — binds nothing).

  • The other clause pattern is nil or _.
  • When the other clause is the catch-all _, the `[__]` clause comes
    first (otherwise _ shadows it and the `[__]` body is dead code —
    converting to an if would change the result). When the other clause is nil the two patterns are disjoint, so either order is safe.

The [_ | _] body becomes the do branch and the nil/_ body the else branch, regardless of source order.

Does NOT fire (deliberately dropped — not provably behaviour-preserving)

  • Regex.run/3 with options. capture: :none (and :all_but_first with no subpatterns) returns [] on a match, which [_ | _] does not match — the two forms disagree, so any 3-argument call is skipped.
  • A bound head ([match | _]) — the body reads the capture, which Regex.match?/2 does not provide.

  • More than two clauses, or specific-capture patterns (["x"], [_, a, b], []) — these inspect the captures, not mere existence.
  • A single clause, or a second clause that does not cover nil — the original raises CaseClauseError on a no-match where an if would not.
  • A named catch-all (other ->) — its body may read the bound nil.
  • Guarded clauses.