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

Reply via email to