My intended use was to utiliize an enum list in user input validation.
Returning an enum allows readable conditions without the overhead of string
comparision.
\-- _probably overkill given my potential use-cases :-)_
import sequtils, strutils
type
OneOfException* = object of ValueError
# Case insensittive prefix-match enum validation
proc oneOf*[T](input: string, choices: seq[T]): T =
# Helper to format raised error
template error[T](text1, text2: string, elements:seq[T]) =
raise OneOfException.newException [
text1, " '", input, "'", " - ", text2, ": ", elements.mapIt($it).join
", "
].join
# Check for prefix match (i.e. h match help)
proc minMatch(source, target: string): bool =
source == target[0..<[source.len, target.len].min]
let
toMatch = input.strip.toLowerAscii # Case insensitive
matching = choices.filterIt toMatch.minMatch $it
case matching.len
of 0: error "No match for", "Must be one of", choices
of 1: result = matching[0]
else: error "Ambiguous", "Matches", matching
if isMainModule:
type
Color = enum
red
green
blue
brown
# ...
for text in ["Red", "green", "g", "b", "brown", "BR", "bLu",""]:
try:
let color = text.oneOf Color.toSeq
echo "Converted ", text, " -> ", color, " (", color.int, ")"
except OneOfException as exception:
echo exception.msg
Run
The above produced the following output:
Converted Red -> red (0)
Converted green -> green (1)
Converted g -> green (1)
Ambiguous 'b' - Matches: blue, brown
Converted brown -> brown (3)
Converted BR -> brown (3)
Converted bLu -> blue (2)
Ambiguous '' - Matches: red, green, blue, brown
Run