Command Line Parser Libraryを使ってコマンドライン引数を解析する3 †
前々回、前回と、コマンドライン引数を解析する機能を提供するライブラリ「Command Line Parser Library」について説明してきましたが、今回はその最終回として、解析できなかった時に自動でエラーメッセージを表示したり、オプションの説明を表示したりする機能について説明します。
解析できなかった時や「--help」オプションが指定された時に、自動的にメッセージを表示する †
コマンドライン引数の解析に失敗した時、自動的に指定したメッセージを表示することができます。それには、OptionsクラスにStringを返すメソッドを作成して、HelpOption属性を適用し、表示したいメッセージを返すようにします。
さらにこのメッセージは、アプリケーションに「--help」オプションを指定して起動した時にも表示されます。
例えばOptionsクラスに以下のようなGetUsageメソッドを追加すると、ParseArgumentsメソッドがFalseを返す時、コンソール(標準エラー出力)に「コマンドラインオプションの記述が正しくありません。」と表示されます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| | Public Class Options
<CommandLine.Option("o"c)> _
Public Property OutputFile As String
<CommandLine.Option("v"c)> _
Public Property Overwrite As Boolean
<CommandLine.HelpOption> _
Public Function GetUsage() As String
Return "コマンドラインオプションの記述が正しくありません。" & vbCrLf
End Function
End Class
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| | public class Options
{
[CommandLine.Option('o')]
public string OutputFile
{
get;
set;
}
[CommandLine.Option('v')]
public bool Overwrite
{
get;
set;
}
[CommandLine.HelpOption]
public string GetUsage()
{
return "コマンドラインオプションの記述が正しくありません。\n";
}
}
|
注意 |
前述したように、新しく作成したParserオブジェクトを使って解析を行った場合は、何も表示されない可能性があります。その場合は、HelpWriterプロパティをConsole.Errorにしてください。これについて詳しくは、後述します。
|
補足 |
GetUsageメソッドがなくても、解析に失敗した時(あるいは「--help」が指定された時)にメッセージを表示する方法があります。Parser.ParseArgumentsメソッドの代わりにParser.ParseArgumentsStrictメソッドを使って解析を行うと、自動的にメッセージが表示されます。この時表示されるメッセージは、後述するHelpText.AutoBuildメソッドを使って作成されたものです。
さらにParseArgumentsStrictメソッドは、3番目の引数がない場合は、メッセージを表示後に自動的に「Environment.Exit(1)」を呼び出して、アプリケーションを終了させます。3番目の引数にデリゲートが指定されていた場合は、それを実行します。
|
オプションの説明文を作成する †
通常のコンソールアプリケーションでは、「/?」のようなオプションによって、使用法と使用できるオプションの説明が表示されます。Command Line Parser LibraryではHelpTextクラスを使うことによって、オプションの説明文を簡単に作成することができます。
そのための準備として、Option属性のHelpTextプロパティを使って、オプションに説明を記述しておきます。また、オプションがBoolean型ではなく、オプションの後に値を記述する必要があるならば、値の説明をMetaValueプロパティに記述します。
このようにしておけば、HelpTextクラスのAddOptionsメソッドを使って、オプションの説明を作成できます。また、HelpText.AddPreOptionsLineメソッドによってオプションの説明の上に表示するメッセージを、HelpText.AddPostOptionsLineメソッドによって下に表示するメッセージを追加できます。
このようにして、使用法とオプションの説明を表示する例を示します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
| | Public Class Options
<CommandLine.Option("o"c, "output", Required:=True, _
HelpText:="出力先のファイル名", MetaValue:="ファイル")> _
Public Property OutputFile As String
<CommandLine.Option("v"c, HelpText:="ファイルを上書き保存する")> _
Public Property Overwrite As Boolean
<CommandLine.HelpOption> _
Public Function GetUsage() As String
Dim help = New CommandLine.Text.HelpText()
help.AddDashesToOption = True
help.AddPreOptionsLine("使用法: TestApp -o ファイル [-v]")
help.AddPreOptionsLine("")
help.AddPreOptionsLine("オプション:")
help.AddOptions(Me, "[必須]")
help.AddPostOptionsLine("詳しくは、ヘルプをご覧ください。")
help.AddPostOptionsLine("")
Return help
End Function
End Class
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
| | public class Options
{
[CommandLine.Option('o', "output", Required = true,
HelpText = "出力先のファイル名", MetaValue = "ファイル")]
public string OutputFile
{
get;
set;
}
[CommandLine.Option('v', HelpText="ファイルを上書き保存する")]
public bool Overwrite
{
get;
set;
}
[CommandLine.HelpOption]
public string GetUsage()
{
var help = new CommandLine.Text.HelpText();
help.AddDashesToOption = true;
help.AddPreOptionsLine("使用法: TestApp -o ファイル [-v]");
help.AddPreOptionsLine("");
help.AddPreOptionsLine("オプション:");
help.AddOptions(this, "[必須]");
help.AddPostOptionsLine("詳しくは、ヘルプをご覧ください。");
help.AddPostOptionsLine("");
return help;
}
}
|
このようにすると、解析に失敗した時、以下のように表示されるようになります。
使用法: TestApp -o ファイル [-v]
オプション:
-o ファイル, --output=ファイル [必須] 出力先のファイル名
-v ファイルを上書き保存する
--help Display this help screen.
詳しくは、ヘルプをご覧ください。
ヘルプを表示するオプションを「--help」以外にする †
「--help」というオプションによってもGetUsageが返すメッセージを表示することができますが、この名前を変更することもできます。このオプションは、GetUsageメソッドに適用されているHelpOption属性によって決められており、Option属性と同じ方法(前号で説明しています)でオプション名を変更できます。
さらに、HelpOptionもHelpTextプロパティによって、「--help」オプションの説明を記述(変更)できます。
例えばGetUsageメソッドに適用するHelpOption属性を次のように変更してみましょう。
1
2
| | <CommandLine.HelpOption("?"c, HelpText:="この説明画面を表示します")> _
Public Function GetUsage() As String
|
1
2
3
| | [CommandLine.HelpOption('?' , HelpText="この説明画面を表示します")]
public string GetUsage()
|
するとメッセージは「-?」で表示できて「--help」では表示できなくなり、メッセージの内容も以下のように変わります。
使用法: TestApp -o ファイル [-v]
オプション:
-o ファイル, --output=ファイル [必須] 出力先のファイル名
-v ファイルを上書き保存する
-? この説明画面を表示します
詳しくは、ヘルプをご覧ください。
エラーの理由によって表示するメッセージを変える †
Optionsクラスに、ParserState属性を適用したIParserStateのプロパティを用意すると、解析に失敗した理由を知ることができるようになります。ただし分かるのは、必須のオプションが指定されていない時、フォーマットが間違えている時、排他的なオプションが指定されている時のみです。不明なオプションが付けられていた場合は、GetUsageメソッドは呼び出されますが、この方法ではエラーの原因を知ることはできないようです。
さらに、エラーがあった時は、HelpText.RenderParsingErrorsTextメソッドによってエラーメッセージを自動的に作成できます。
これらを使用した例を以下に示します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
| | Public Class Options
<CommandLine.Option("o"c, "output", Required:=True, _
HelpText:="出力先のファイル名", MetaValue:="ファイル")> _
Public Property OutputFile As String
<CommandLine.Option("v"c, HelpText:="ファイルを上書き保存する")> _
Public Property Overwrite As Boolean
<CommandLine.Option("s"c, HelpText:="出力するファイルのサイズ", _
MetaValue:="サイズ")> _
Public Property Size As Integer
<CommandLine.ParserState> _
Public Property LastParserState As CommandLine.IParserState
<CommandLine.HelpOption> _
Public Function GetUsage() As String
Dim help = New CommandLine.Text.HelpText()
help.AddDashesToOption = True
If Me.LastParserState Is Nothing Then
help.AddPreOptionsLine("使用できるオプション一覧:")
ElseIf Me.LastParserState.Errors IsNot Nothing AndAlso _
Me.LastParserState.Errors.Count > 0 Then
Dim errMsg As String = help.RenderParsingErrorsText(Me, 2)
help.AddPreOptionsLine(errMsg)
Else
help.AddPreOptionsLine("理解できないオプションが含まれています。")
help.AddPreOptionsLine("以下に使用できるオプションの一覧を示します。")
End If
help.AddOptions(Me)
help.AddPostOptionsLine("")
Return help
End Function
End Class
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
| | public class Options
{
[CommandLine.Option('o', "output", Required = true,
HelpText = "出力先のファイル名", MetaValue = "ファイル")]
public string OutputFile
{
get;
set;
}
[CommandLine.Option('v', HelpText = "ファイルを上書き保存する")]
public bool Overwrite
{
get;
set;
}
[CommandLine.Option('s',
HelpText = "出力するファイルのサイズ", MetaValue = "サイズ")]
public int Size
{
get;
set;
}
[CommandLine.ParserState]
public CommandLine.IParserState LastParserState
{
get;
set;
}
[CommandLine.HelpOption]
public string GetUsage()
{
var help = new CommandLine.Text.HelpText();
help.AddDashesToOption = true;
if (this.LastParserState == null)
{
help.AddPreOptionsLine("使用できるオプション一覧:");
}
else if (this.LastParserState.Errors != null &&
this.LastParserState.Errors.Count > 0)
{
string errMsg = help.RenderParsingErrorsText(this, 2);
help.AddPreOptionsLine(errMsg);
}
else
{
help.AddPreOptionsLine("理解できないオプションが含まれています。");
help.AddPreOptionsLine("以下に使用できるオプションの一覧を示します。");
}
help.AddOptions(this);
help.AddPostOptionsLine("");
return help;
}
}
|
上記のコードで、必須オプションの欠落とフォーマットのエラーがあった時に表示されるメッセージは、以下のようになります。
-s option violates format.
-o/--output required option is missing.
-o ファイル, --output=ファイル Required. 出力先のファイル名
-v ファイルを上書き保存する
-s サイズ 出力するファイルのサイズ
--help Display this help screen.
さらに説明を補足します。上記の例では、エラーの原因が「this.LastParserState.Errors」にコレクションとして格納されます。「this.LastParserState」がnullの時は「--help」オプションで表示した時で、「this.LastParserState.Errors.Count」が0の時は不明なオプションが指定された時だと思われますが、これはあくまで推測です。
「this.LastParserState.Errors」はParsingErrorオブジェクトのコレクションですが、ParsingErrorクラスが持つ3つのBoolean型のプロパティ、ViolatesRequired、ViolatesFormat、ViolatesMutualExclusivenessによって、エラーの理由が分かります。ViolatesRequiredがTrueなら必須のオプションが指定されていない、ViolatesFormatがTrueならフォーマットが間違いている、ViolatesMutualExclusivenessがTrueなら排他的なオプションが指定されている時です。
また、ParsingErrorオブジェクトのBadOptionプロパティによって、エラーの原因となったオプションの名前が分かります。
これらを駆使してエラーメッセージを自分で作成することができますが、上記の例では手を抜いて、RenderParsingErrorsTextメソッドで自動的に作成しています。RenderParsingErrorsTextメソッドで作成したエラーメッセージは英語ですが、これを日本語にする方法は、後述します。
自動でメッセージを作成する最も簡単な方法 †
HelpText.AutoBuildとHelpText.DefaultParsingErrorsHandlerを使えば、たった1行でメッセージを作成できます。
1
2
3
4
5
6
7
8
| | <CommandLine.HelpOption> _
Public Function GetUsage() As String
Return CommandLine.Text.HelpText.AutoBuild(Me, _
Sub(current) CommandLine.Text.HelpText.DefaultParsingErrorsHandler( _
Me, current))
End Function
|
1
2
3
4
5
6
7
8
| | [CommandLine.HelpOption]
public string GetUsage()
{
return CommandLine.Text.HelpText.AutoBuild(this, current =>
CommandLine.Text.HelpText.DefaultParsingErrorsHandler(this, current));
}
|
このようにした時に表示されるメッセージは、例えば次にようになります。(ここでは、2つのエラーが発生しています。)
TestApplication 1.0.0.0
Copyright c 2013 DOBON!
ERROR(S):
-s option violates format.
-o/--output required option is missing.
-o ファイル, --output=ファイル Required. 出力先のファイル名
-v ファイルを上書き保存する
-s サイズ 出力するファイルのサイズ
--help Display this help screen.
この中で、「TestApplication」というのはアプリケーションのアセンブリ情報で「タイトル」に指定されている文字列です。同様に、「1.0.0.0」は「アセンブリバージョン」、「Copyright c 2013」は「著作権」、「DOBON!」は「会社名」です。アセンブリ情報を変更すると、ここに表示される内容もそれに合わせて変わります。
補足 |
このようなアプリケーションのタイトルとバージョンの説明はHeadingInfo.Defaultで、著作権と会社名の説明はCopyrightInfo.Defaultで取得できます。
|
さらに、「AssemblyInfo.cs」(VB.NETでは「AssemblyInfo.vb」)でAssemblyLicense属性を使うとライセンス情報を、AssemblyUsage属性を使うとアプリケーションの使い方を表示できるようになります。
例えばAssemblyInfo.csに次のような記述を追加したとします。
1
2
3
4
5
| | <Assembly: CommandLine.AssemblyLicense( _
"このアプリケーションは、MITライセンスで公開します。", _
"The MIT License (MIT) <http://opensource.org/licenses/mit-license.html>.")>
<Assembly: CommandLine.AssemblyUsage( _
"使用法: TestApp -o ファイル [-v] [-s サイズ]", _
" TestApp --output=ファイル")>
|
1
2
3
4
5
6
| | [assembly: CommandLine.AssemblyLicense(
"このアプリケーションは、MITライセンスで公開します。",
"The MIT License (MIT) <http://opensource.org/licenses/mit-license.html>.")]
[assembly: CommandLine.AssemblyUsage(
"使用法: TestApp -o ファイル [-v] [-s サイズ]",
" TestApp --output=ファイル")]
|
するとエラーメッセージは、次のように変わります。
TestApplication 1.0.0.0
Copyright c 2013 DOBON!
ERROR(S):
-s option violates format.
-o/--output required option is missing.
このアプリケーションは、MITライセンスで公開します。
The MIT License (MIT) <http://opensource.org/licenses/mit-license.html>.
使用法: TestApp -o ファイル [-v] [-s サイズ]
TestApp --output=ファイル
-o ファイル, --output=ファイル Required. 出力先のファイル名
-v ファイルを上書き保存する
-s サイズ 出力するファイルのサイズ
--help Display this help screen.
エラーメッセージを日本語にする †
RenderParsingErrorsTextやAutoBuild(DefaultParsingErrorsHandler)では、エラーメッセージが英語で表示されます。しかし、BaseSentenceBuilderの派生クラスを作成すると英語以外でも表示できるようなので、試してみました。
まず以下のようなBaseSentenceBuilderの派生クラス「JapaneseSentenceBuilder」を作成します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
| | Public Class JapaneseSentenceBuilder
Inherits CommandLine.Text.BaseSentenceBuilder
Public Overrides ReadOnly Property AndWord() As String
Get
Return "且つ"
End Get
End Property
Public Overrides ReadOnly Property ErrorsHeadingText() As String
Get
Return "エラー:"
End Get
End Property
Public Overrides ReadOnly Property OptionWord() As String
Get
Return "オプション"
End Get
End Property
Public Overrides ReadOnly Property RequiredOptionMissingText() As String
Get
Return "必須のオプションが指定されていません"
End Get
End Property
Public Overrides ReadOnly Property ViolatesFormatText() As String
Get
Return "書式が正しくありません"
End Get
End Property
Public Overrides ReadOnly Property ViolatesMutualExclusivenessText() As String
Get
Return "一緒に使用できないオプションが使われています"
End Get
End Property
End Class
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
| | public class JapaneseSentenceBuilder : CommandLine.Text.BaseSentenceBuilder
{
public override string AndWord
{
get { return "且つ"; }
}
public override string ErrorsHeadingText
{
get { return "エラー:"; }
}
public override string OptionWord
{
get { return "オプション"; }
}
public override string RequiredOptionMissingText
{
get { return "必須のオプションが指定されていません"; }
}
public override string ViolatesFormatText
{
get { return "書式が正しくありません"; }
}
public override string ViolatesMutualExclusivenessText
{
get { return "一緒に使用できないオプションが使われています"; }
}
}
|
このクラスを使えば、RenderParsingErrorsTextやDefaultParsingErrorsHandlerが返すエラーメッセージを日本語にできます。ただし、先ほどのようにAutoBuildメソッドを使って1発でメッセージを作成する時には、このクラスを使って日本語化する方法が用意されていません。
それでもあえてAutoBuildを使う場合は、例えば以下のような方法が考えられます。
1
2
3
4
5
6
7
8
9
10
11
12
| | <CommandLine.HelpOption> _
Public Function GetUsage() As String
Dim help = CommandLine.Text.HelpText.AutoBuild(Me)
Dim jhelp = New CommandLine.Text.HelpText(New JapaneseSentenceBuilder())
CommandLine.Text.HelpText.DefaultParsingErrorsHandler(Me, jhelp)
help.AddPreOptionsLine(jhelp)
Return help
End Function
|
1
2
3
4
5
6
7
8
9
10
11
12
13
| | [CommandLine.HelpOption]
public string GetUsage()
{
var help = CommandLine.Text.HelpText.AutoBuild(this);
var jhelp = new CommandLine.Text.HelpText(new JapaneseSentenceBuilder());
CommandLine.Text.HelpText.DefaultParsingErrorsHandler(this, jhelp);
help.AddPreOptionsLine(jhelp);
return help;
}
|
すると、エラーメッセージは以下のようになります。
TestApplication 1.0.0.0
Copyright c 2013
このアプリケーションは、MITライセンスで公開します。
The MIT License (MIT) <http://opensource.org/licenses/mit-license.html>.
使用法: TestApp -o ファイル [-v] [-s サイズ]
TestApp --output=ファイル
エラー:
-s オプション 書式が正しくありません.
-o/--output 必須のオプションが指定されていません.
-o ファイル, --output=ファイル Required. 出力先のファイル名
-v ファイルを上書き保存する
-s サイズ 出力するファイルのサイズ
--help Display this help screen.
エラーメッセージが表示される位置が変わりましたが、エラーメッセージが日本語化されました。
メッセージをコンソール以外に表示する †
前に触れましたが、ParserクラスのHelpWriterプロパティによって、メッセージが出力される先が決まります。HelpWriterプロパティにStreamが指定されていればそのStreamに書き込み、nullであればどこにも書き込みません。
Parser.DefaultのHelpWriterはConsole.Errorなので、標準エラー出力ストリームに書き込みます。しかし、新しく作成したParserオブジェクトのHelpWriterはnullなので、どこにも書き込みません。
コンソールアプリケーションであれば標準エラー出力ストリームへの書き込みで問題ないかもしれませんが、Windowsフォームアプリケーションであればそうもいかないでしょう。そのような場合は、例えばParserのHelpWriterプロパティをStringWriterにすることで、メッセージを取得することができます。
以下にその例を示します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| | Module Module1
Sub Main(args As String())
Dim opts = New Options()
Dim sw = New System.IO.StringWriter()
Dim p = New CommandLine.Parser(Sub(w) w.HelpWriter = sw)
Dim isSuccess As Boolean = p.ParseArguments(args, opts)
sw.Close()
Dim helpMsg As String = sw.ToString()
If Not String.IsNullOrEmpty(helpMsg) Then
Console.WriteLine(helpMsg)
End If
Console.ReadLine()
End Sub
End Module
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| | static void Main(string[] args)
{
var opts = new Options();
var sw = new System.IO.StringWriter();
var p = new CommandLine.Parser(with => with.HelpWriter = sw);
bool isSuccess = p.ParseArguments(args, opts);
sw.Close();
string helpMsg = sw.ToString();
if (!string.IsNullOrEmpty(helpMsg))
{
Console.WriteLine(helpMsg);
}
Console.ReadLine();
}
|
最後に †
Command Line Parser Libraryについて長々と説明してきましたが、今回で終わりにします。まだ紹介していない機能もいろいろありますので、興味のある方は調べてみてください。
ページ情報 |
- 作成日 : 2013-04-22 (月) 01:36:11
- 作成者 : DOBON!
- 最終編集日 : 2013-04-22 (月) 01:36:11
- 最終編集者 : DOBON!
|