parseopt, parsecfg - Nimでの実行時設定
アプリケーションに実行時設定を渡す方法としては大きく分けて「コマンドライン引数」か「設定ファイル」の2つがある。
最近の言語なら、いずれも解析ライブラリが存在している。Nimもご多分に漏れず標準モジュールに存在する。
- Nim ver.0.19.0
コマンドライン引数解析
parseopt
Pythonのargparseはとても細かく設定できて、パース前に「キーワードAはint型が来る前提で、デフォルト値は4で、BとCはいずれかが指定されていないとエラーにして」など設定した上でパースを実行する。
Nimの方はそこまで親切では無いが、とりあえずパースしてキーワードと値(あれば)をセットにするまでやってくれる。後はイテレートして適宜取得する感じ。必要な指定が無いとか重複してるとかのチェックは自分で実装する必要がある。
ただ、正直これなら最初から自分で実装しても大きくは変わらない……くらいの機能である点は否めない。
構文 | 種別 | キー | 値 |
---|---|---|---|
--key=val --key:val | cmdLongOption | key | val |
-kval -k=val -k:val | cmdShortOption | k | val |
--key | cmdLongOption | key | ““ |
-k | cmdShortOption | k | ”“ |
key | cmdArgument | key | ”“ |
--key val | cmdLongOption + cmdArgument | key + val | ”” + ““ |
「--key val
」「-k val
」式の文法はサポートして無くて、値なしのキーと位置引数に分けて解釈される。
import os, strutils, parseopt # パラメータを格納する独自クラス type Param* = object pos1*: string pos2*: string left*: bool right*: int debug*: int var param = Param() # コマンドラインパーサ # 実験のため引数で与えているが、省略すると実際のコマンドライン引数が使われる var p = initOptParser("pos1 --left --debug:3 -l -r=2 pos2") # 位置引数の順番をカウント var posCnt = 0 # イテレートして種別、キー、値を順次取得 for kind, key, val in p.getopt(): case kind of cmdArgument: case posCnt of 0: param.pos1 = key of 1: param.pos2 = key else: discard posCnt += 1 of cmdLongOption, cmdShortOption: case key of "left", "l": param.left = true of "right", "r": param.right = val.parseInt of "debug": param.debug = val.parseInt of cmdEnd: assert(false) # cannot happen echo $param # => # (pos: "pon1", left: true, right: 2, debug: 3)
shortNoVal, longNoVal
を与えると、キーワードでないことを明言できる(ざっくりとした理解)……のだが、どうも目的や挙動がよくわからない。
docopt
こちらは第三者モジュール。本家はPythonだが、Nim移植版が存在する。
> nimble install docopt
docoptは「所定のルールに従ったヘルプを文字列で与えることで、パーサを組み立てる」という逆転の発想のライブラリ。
より複雑なルールを持ったパーサを、直感的にわかりやすい記法で作成できるので、標準モジュールのparseopt以上のことがしたくなったらこちらが楽。
設定ファイル解析
parsecfg
ini等でよくある、セクション毎に分かれた設定ファイルをパースできる。上記の公式解説に例もありわかりやすい。
[Section] key1 = val1 key2: val2 ; Comment
import os, parsecfg, strutils var cfg = loadConfig("settings.cfg") key1 = cfg.getSectionValue("Section", "key1") echo key1 # => val
変数は使えない模様。
また、Windowsのドライブパスに含まれる「:」はキーと値の区切り文字として解釈されバグる恐れがあるため、全体を””
でくくる必要がある。
さらに「\」はエスケープ文字として扱われるため、r“string”
でエスケープ無効とするか、\\
と2つ重ねる必要がある。
.ini記法のパーサは様々な言語に存在しても、この辺の細かな文字列の解釈の違いは言語毎に異なるため、言語毎に留意が必要。