Q:

Testing if a docopt command-line option is set in nim

I'm trying to write a nim program that can read either from the standard input or from a file given as a command-line option. I use docopt to parse the command line.
import docopt

const doc = """
This program takes input from a file or from stdin.

Usage:
  testinput [-i <filename> | --input <filename>]

-h --help              Show this help message and exit.
-i --input <filename>  File to use as input.
"""

when isMainModule:
  let args = docopt(doc)
  var inFilename: string
  for opt, val in args.pairs():
    case opt
    of "-i", "--input":
      inFilename = $args[opt]
    else:
      echo "Unknown option" & opt
      quit(QuitFailure)
  let inputSource =
    if inFilename.isNil:
      stdin
    else:
      echo "We have inFilename: " & inFilename
      open(inFilename)

The program compiles.
It doesn't crash when I give it a file on the command line:
$ ./testinput -i testinput.nim
We have inFilename: testinput.nim

But I get an IOError if I try to feed it from its stdin:
$ ./testinput < testinput.nim
We have inFilename: nil
testinput.nim(28)        testinput
system.nim(2833)         sysFatal
Error: unhandled exception: cannot open: nil [IOError]

How come inFilename.isNil is false, and yet the execution of the else branch tells me that inFilename "is" nil?
Is there a correct and elegant way to do this, using docopt?

A:

I'm not familiar with docopt, but it seems to create an entry for each option in the doc, not for the options specified by user so your code's been getting args == {"--input": nil} and stringifying the nil.
The following will work correctly:
import docopt

const doc = """
This program takes input from a file or from stdin.

Usage:
  testinput [-i <filename> | --input <filename>]

-h --help              Show this help message and exit.
-i --input <filename>  File to use as input.
"""

when isMainModule:
  let args = docopt(doc)
  var inFilename: string
  if args["--input"]:
    inFilename = $args["--input"]
  if not inFilename.isNil:
    echo "We have inFilename: " & inFilename
  let inputSource =
    if inFilename.isNil:
      stdin
    else:
      open(inFilename)

Also note that you don't have to check for "-i" option as docopt knows it's an alias to "--input".

