voile.parseopt
コマンドライン引数のパーサー
getoptと同じくコマンドラインの解析を行う。
getoptとの違いは、getoptは関数の引数に基づいて引数の解析を行うが、
本モジュールの parseOptions は、構造体の変数を引数に取ることで、構造体メンバ
に関連付けられたUDAによりコマンドライン引数の解析を行う。
@help("Help messages for heading of application.\n") struct Dat { @help("Description of `value`") string value; string nonHelpedValue; @ignore string ignoredValue; @opt("a|aaaa") @help("Description of `i32value`") int i32value; @opt("f|ff") int f32value; }構造体(型)に付与できるUDAは以下の通り
- help(str) : アプリケーションのヘルプメッセージ
- caseSensitive : コマンドライン引数の大文字小文字を区別するかどうか。デフォルトは区別しない。
- passThrough : 解釈されなかったコマンドライン引数を無視するか例外としてはじくか。デフォルトは例外としてはじく。
- binding : 短いコマンドライン引数を、まとめて指定できるか(
-abc
で-a -b -c
と同じ解釈にさせるかどうか) - assignChar(str) : コマンドライン引数の「割り当て」に使用する文字を指定できる。(デフォルトは
=
。-a=xxx
や--arg=xxx
など。区切り文字を変更可能。) - arraySeparator(str) : コマンドライン引数の配列の区切り文字を指定できる。(デフォルトは
,
(カンマ)。-a=xxx,yyy,zzz
の,
を変更可能。) - endOfOptions(str) : コマンドライン引数として解釈させる最後の文字を指定できる。(デフォルトは
--
で、-a=xxx -b=yyy -- -c=zzz
では、-a
と-b
だけ解釈させる区切り文字として作用する。この区切り文字を変更可能。) - shortOpt(str) : 短いコマンドライン引数として解釈させるprefixを指定できる。(デフォルトは
-
。-a
などのように使われる。) - longOpt(str) : 短いコマンドライン引数として解釈させるprefixを指定できる。(デフォルトは
--
。--arg
などのように使われる。)
- help(str) : 引数のヘルプメッセージ
- opt(str) : 引数。
"a|args"
とすることで、-a
と--args
を同時に定義可能。指定しなければオプションとして指定できない。 - required : 引数を指定することを必須化する。デフォルトは
false
。 - convBy!fn : 指定した関数
fn
によって引数の値をメンバ変数の型に変換する。 - ignore : 指定したメンバーをコマンドライン引数の解釈に使用しない。
- convByが指定されている引数
- T function(string arg)
- void function(ref T dst, string arg)
- void function(out T dst, string arg)
- void function(in S dat, ref T dst, string arg)
- void function(in S dat, out T dst, string arg)
- void function(ref S dat, string arg)
- bool : 真偽値
- string : 文字列型
- T[] : 配列。std.conv.toにより、文字列がTに変換可能。
- V[K] : 連想配列。std.conv.toにより文字列がV, Kに変換可能。
- T : std.conv.toにより、文字列がTに変換可能。
- void function(bool shortPrefix, string arg)
- void function(string prefix, string arg)
- void function(string arg)
- void function(bool enabled)
- void function()
- pure nothrow @nogc @safe Help
help
(string str); - pure nothrow @nogc @safe CaseSensitive
caseSensitive
(); - pure nothrow @nogc @safe PassThrough
passThrough
(); - pure nothrow @nogc @safe Binding
binding
(); - pure nothrow @nogc @safe AssignChar
assignChar
(dchar c = '='); - pure nothrow @nogc @safe ArraySeparator
arraySeparator
(dchar c = ','); - EndOfOptions
endOfOptions
(string str); - pure nothrow @nogc @safe Opt
opt
(string str); - pure nothrow @nogc @safe Req
required
(); - pure nothrow @safe OptShort
optShort
(string[] str...); - pure nothrow @safe OptLong
optLong
(string[] str...); - template
convBy
(alias fn) - alias
ignore
= Ignore; - pure nothrow @nogc @safe TypeOption
typeOption
(string help = null, bool caseSensitive = false, bool passThrough = false, bool binding = false, dchar assignChar = '=', dchar arraySeparator = ',', string endOfOptions = "--", string[] shortOpt = ["-"], string[] longOpt = ["--"]); - pure nothrow @nogc @safe Option
option
(string opt, string help = null, bool required = false); - class
ParseOptException
: object.Exception; - struct
HelpInformation
; -
- string
help
; - bool
wanted
; - const pure nothrow @nogc T
opCast
(T)()
if(is(T == bool));
- @safe HelpInformation
parseOptions
(T)(ref string[] args, ref T dat); - Examples:
import std.exception; struct Dat { @opt("a|arg") string value; @opt("b|arg2") int intValue; } Dat dat; string[] args; args = ["xxx", "-a=vvv"]; args.parseOptions(dat); assert(dat.value == "vvv"); dat = Dat.init; args = ["xxx", "-ac=vvv"]; args.parseOptions(dat); assert(dat.value == "c=vvv"); dat = Dat.init; args = ["xxx", "-a=vvv", "--arg2=123"]; args.parseOptions(dat); assert(dat.intValue == 123);
Examples:auto args = ["prog", "--foo", "-b"]; @help("Some information about the program.") struct Dat { @option("foo|f", "Some information about foo.") bool foo; @option("bar|b", "Some help message about bar.") bool bar; } Dat dat; if (auto helpWanted = args.parseOptions(dat)) { import std.stdio; writeln(helpWanted.help); assert(0); } assert(dat.foo); assert(dat.bar);
Examples:import std.exception : assertThrown; string[] args = ["program", "-a"]; @passThrough struct Dat { @(.opt("a")) bool opt; } Dat dat; args.parseOptions(dat); assert(dat.opt); @caseSensitive struct Dat2 { @help("help string") @(.opt("a")) bool opt; } Dat2 dat2; args = ["program", "-a"]; args.parseOptions(dat2); assert(dat2.opt); struct Dat3 { @help("forgot to put a string") @(.opt("a")) bool opt; } Dat3 dat3; args = ["program", ""]; assertThrown( args.parseOptions(dat3));
Examples: This behavior is different from Phobos' std.getopt.import std.algorithm.searching : startsWith; @arraySeparator(',') struct Dat { @opt("m") string[string] mapping; } Dat dat; string[] args = ["testProgram", "-m", "a=b,c=\"d,e,f\""]; // getopt may thrown but parseOptions is not args.parseOptions(dat); assert("a" in dat.mapping); assert("c" in dat.mapping); assert("e" in dat.mapping); assert("f\"" in dat.mapping); assert(dat.mapping["a"] == "b"); assert(dat.mapping["c"] == "\"d"); assert(dat.mapping["e"] == null); assert(dat.mapping["f\""] == null);
Examples:import std.conv; @arraySeparator(',') struct Dat { @opt("n|name") string[] names; } Dat dat; auto args = ["program.name", "-nfoo,bar,baz"]; args.parseOptions(dat); assert(dat.names == ["foo", "bar", "baz"], to!string(dat.names)); dat = Dat.init; args = ["program.name", "-n", "foo,bar,baz"]; args.parseOptions(dat); assert(dat.names == ["foo", "bar", "baz"], to!string(dat.names)); dat = Dat.init; args = ["program.name", "--name=foo,bar,baz"]; args.parseOptions(dat); assert(dat.names == ["foo", "bar", "baz"], to!string(dat.names)); dat = Dat.init; args = ["program.name", "--name", "foo,bar,baz"]; args.parseOptions(dat); assert(dat.names == ["foo", "bar", "baz"], to!string(dat.names));
Examples:import std.conv; struct Dat { @opt("values|v") int[string] values; void hogehoge(string x) /+ pure but not annotation +/ { } } Dat dat; dat.values = dat.values.init; auto args = ["program.name", "-vfoo=0,bar=1,baz=2"]; args.parseOptions(dat); assert(dat.values == ["foo":0, "bar":1, "baz":2], to!string(dat.values)); dat.values = dat.values.init; args = ["program.name", "-v", "foo=0,bar=1,baz=2"]; args.parseOptions(dat); assert(dat.values == ["foo":0, "bar":1, "baz":2], to!string(dat.values)); dat.values = dat.values.init; args = ["program.name", "--values=foo=0,bar=1,baz=2"]; args.parseOptions(dat); assert(dat.values == ["foo":0, "bar":1, "baz":2], to!string(dat.values)); dat.values = dat.values.init; args = ["program.name", "--values", "foo=0,bar=1,baz=2"]; // call from pure () pure { args.parseOptions(dat); } (); assert(dat.values == ["foo":0, "bar":1, "baz":2], to!string(dat.values));
Examples:import std.conv, std.math; static int xxxxx = 10; struct Dat { @opt("foo") @convBy!(a => a ~ a) string valueStr; @ignore static void convBar(ref int dst, string src) { import std.conv; dst = to!int(src); } @ignore static void convHoge(ref Dat dst, string src) { import std.conv, std.range, std.array; auto v = to!int(src); dst.hogeLen = v; dst.hoge = repeat("hoge", v).join; } @opt("bar") @convBy!convBar int valueI32; float valueF32; @ignore size_t hogeLen; @convBy!convHoge string hoge; void fuga(string x) /+ impure +/ { valueF32 += valueI32 + xxxxx; valueI32 += to!int(x); } } Dat dat; dat.valueStr = dat.valueStr.init; dat.valueI32 = dat.valueI32.init; dat.valueF32 = dat.valueF32.init; auto args = ["program.name", "--foo=aaa", "--bar=12345", "--valueF32=10", "--hoge=3", "--fuga=5"]; args.parseOptions(dat); assert(dat.valueStr == "aaaaaa"); assert(dat.valueI32 == 12345+5); assert(dat.valueF32.isClose(10.0f+12345 + 10)); assert(dat.hogeLen == 3); assert(dat.hoge == "hogehogehoge");
Examples:import std.conv, std.math; @passThrough() struct Dat { @opt("foo") int foo; @opt("bar") string bar; } Dat dat; auto args = ["program.name", "--foo=10", "aaa", "--bar=12345", "--valueF32=10", "bbb", "--hoge=", "ccc", "--fuga=5"]; args.parseOptions(dat); assert(dat.foo == 10); assert(dat.bar == "12345"); assert(args == ["program.name", "aaa", "--valueF32=10", "bbb", "--hoge=", "ccc", "--fuga=5"]);