Dartメモ：コマンドライン引数の処理


自分用メモです。

## 引数をとる

```dart:コード
void main(List<String> args) {
    print(args);
}
```

```bash:実行
$ dart hoge1.dart -n -l 3 --some=1 2 3
[-n, -l, 3, --some=1, 2, 3]
```

`hoge1.dart` がargs[0]になったりはせず、純粋に引数がargsに渡されるようだ。

## 引数を解釈する

PythonのargparseみたいなのがDartでは標準パッケージにあるらしい。

* true/falseをもらいたい引数には `addFlag`
	* `--no-xxxxx` という引数を処理したくないときには `negatable: false`
	* デフォルトtrueにしたいときには `defaultsTo: true`
* 値をもらいたい引数には `addOption`


```dart:コード
import 'package:args/args.dart';

void main(List<String> args) {
    val parser = new ArgParser()
                    ..addFlag('no-br', negatable: false, abbr: 'n')
                    ..addOption('length', abbr: 'l')
                    ..addOption('some');
    val argResults = parser.parse(args);

    print(['no-br', argResults['no-br']]);
    print(['length', argResults['length']]);
    print(['some', argResults['some']]);
    print(['rest', argResults.rest]);
}
```

```bash:実行
$ dart hoge1.dart -n -l 3 --some=1 2 3
[no-br, true]
[length, 3]
[some, 1]
[rest, [2, 3]]
```


あとは、サブコマンドもシンプルに `addCommand` で定義できるっぽい。

```dart:コード
import 'package:args/args.dart';

void main(List<String> args) {
    val postParser = new ArgParser()
                    ..addOption('message')
                    ..addOption('token');
    val observeParser = new ArgParser()
                    ..addOption('channel', abbr: 'c')
                    ..addFlag('print');
    val parser = new ArgParser()
                    ..addCommand('post', postParser)
                    ..addCommand('observe', observeParser);

    val argResults = parser.parse(args);

    switch(argResults.command.name) {
        case 'post':        
            print(['message', argResults.command['message']]);
            print(['token', argResults.command['token']]);
            break;
        case 'observe':
            print(['channel', argResults.command['channel']]);
            print(['print', argResults.command['print']]);
            break;
    } 
}
```

```bash:実行
$ dart hoge1.dart post --message hogehoge
[message, hogehoge]
[token, null]
$ dart hoge1.dart observe -c hoge
[channel, hoge]
[print, false]
```

ただ、addCommandよりもCommandRunnerを使うほうが推奨らしい。

```dart:コード
import 'package:args/command_runner.dart';

class PostCommand extends Command {
    final name = "post";
    final description = "Post a new message.";
    PostCommand() {
        argParser
            ..addOption('message')
            ..addOption('token');
    }

    void run() {
        print(['message', argResults['message']]);
        print(['token', argResults['token']]);
    }
}

class ObserveCommand extends Command {
    final name = "observe";
    final description = "Observe user messages via RTM.";
    ObserveCommand() {
        argParser
            ..addOption('channel', abbr: 'c')
            ..addFlag('print');
    }

    void run() {
        print(['channel', argResults['channel']]);
        print(['print', argResults['print']]);
    }
}

void main(List<String> args) {
    new CommandRunner("slack", "Slack Commandline interface")
        ..addCommand(new PostCommand())
        ..addCommand(new ObserveCommand())
        ..run(args);
}
```

```bash:実行
$ dart hoge1.dart post --message hogehoge
[message, hogehoge]
[token, null]
$ dart hoge1.dart observe -c hoge
[channel, hoge]
[print, false]
```

ただ、CommandRunnerは argParserやargResultsが暗黙的に定義されていたり、nameとかdescriptionとかが実は定義必須だったり、暗黙的にいろいろやってるのが若干イマイチ感ある。