测试是否在 nim 中设置了 docopt 命令行选项

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

我正在尝试编写一个 nim 程序,它可以从标准输入或作为命令行选项给出的文件中读取。我使用docopt来解析命令行。

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)

程序编译。

当我在命令行上给它一个文件时它没有崩溃:

$ ./testinput -i testinput.nim
We have inFilename: testinput.nim

但是如果我尝试从它的标准输入中输入它,我会得到一个 IOError:

$ ./testinput < testinput.nim
We have inFilename: nil
testinput.nim(28)        testinput
system.nim(2833)         sysFatal
Error: unhandled exception: cannot open: nil [IOError]

为什么inFilename.isNil是假的,但是else分支的执行告诉我inFilename "is" nil?

是否有使用 docopt 的正确而优雅的方法?

我不熟悉 docopt,但它似乎为文档中的每个选项创建了一个条目,而不是为用户指定的选项创建了一个条目,因此您的代码一直在 args == {"--input": nil} 并将 nil.

以下将正常工作:

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)

另请注意,您不必检查 "-i" 选项,因为 docopt 知道它是 "--input".

的别名

与其将选项的值转换为带有 $ 的字符串,不如将其保留为 Value,这是 docopt.[=21 返回的类型=]

根据 documentation:

vkNone (No Value)

This kind of Value appears when there is an option which hasn't been set and has no default. It is false when converted toBool

显然可以在布尔表达式中使用选项的值,它似乎被自动解释为 bool:

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: Value
  for opt, val in args.pairs():
    case opt
    of "-i", "--input":
      inFilename = val
    else:
      echo "Unknown option" & opt
      quit(QuitFailure)
  let inputSource =
    if not bool(inFilename):
      stdin
    else:
      echo "We have inFilename: " & $inFilename
      open($inFilename)

此行为的另一种用法在 中给出,避免设置变量,因此保留它 nil