diff --git a/CHANGELOG.md b/CHANGELOG.md index e34bb8c..16515ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 2.4.2 + +* Change the validation of `mandatory` options; they now perform validation when + the value is retrieved (from the `ArgResults` object), instead of when the + args are parsed. + ## 2.4.1 * Add a `CONTRIBUTING.md` file; move the publishing automation docs from the diff --git a/README.md b/README.md index 4d5613d..e47bfc7 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,8 @@ Parses raw command-line arguments into a set of options and values. -This library supports [GNU][] and [POSIX][] style options, and it works -in both server-side and client-side apps. +This library supports [GNU][] and [POSIX][] style options, and it works in both +server-side and client-side apps. ## Defining options @@ -78,8 +78,8 @@ The callbacks for all options are called whenever a set of arguments is parsed. If an option isn't provided in the args, its callback is passed the default value, or `null` if no default value is set. -If an option is `mandatory` but not provided, the parser throws an -[`ArgParserException`][ArgParserException]. +If an option is `mandatory` but not provided, the results object throws an +[`ArgumentError`][ArgumentError] on retrieval. ```dart parser.addOption('mode', mandatory: true); diff --git a/lib/src/arg_results.dart b/lib/src/arg_results.dart index 0e49a76..3761ab1 100644 --- a/lib/src/arg_results.dart +++ b/lib/src/arg_results.dart @@ -65,7 +65,12 @@ class ArgResults { throw ArgumentError('Could not find an option named "$name".'); } - return _parser.options[name]!.valueOrDefault(_parsed[name]); + final option = _parser.options[name]!; + if (option.mandatory && !_parsed.containsKey(name)) { + throw ArgumentError('Option $name is mandatory.'); + } + + return option.valueOrDefault(_parsed[name]); } /// The names of the available options. diff --git a/lib/src/parser.dart b/lib/src/parser.dart index 0862ce9..3c5dfed 100644 --- a/lib/src/parser.dart +++ b/lib/src/parser.dart @@ -95,14 +95,15 @@ class Parser { _grammar.options.forEach((name, option) { var parsedOption = _results[name]; - // Check if an option was mandatory and exist - // if not throw an exception + var callback = option.callback; + if (callback == null) return; + + // Check if an option is mandatory and was passed; if not, throw an + // exception. if (option.mandatory && parsedOption == null) { throw ArgParserException('Option $name is mandatory.'); } - var callback = option.callback; - if (callback == null) return; // ignore: avoid_dynamic_calls callback(option.valueOrDefault(parsedOption)); }); diff --git a/pubspec.yaml b/pubspec.yaml index 0202894..dec55a9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: args -version: 2.4.1 +version: 2.4.2 description: >- Library for defining parsers for parsing raw command-line arguments into a set of options and values using GNU and POSIX style options. diff --git a/test/command_runner_test.dart b/test/command_runner_test.dart index 9207c3b..9031dd1 100644 --- a/test/command_runner_test.dart +++ b/test/command_runner_test.dart @@ -736,7 +736,7 @@ Run "test help" to see global options.''')); runner.addCommand(subcommand); expect( () => runner.run([subcommand.name]), - throwsA(isA().having((e) => e.message, 'message', + throwsA(isA().having((e) => e.message, 'message', contains('Option mandatory-option is mandatory')))); expect(await runner.run([subcommand.name, '--mandatory-option', 'foo']), 'foo'); diff --git a/test/parse_test.dart b/test/parse_test.dart index b68241a..318d2b5 100644 --- a/test/parse_test.dart +++ b/test/parse_test.dart @@ -514,14 +514,17 @@ void main() { test('throw if no args', () { var parser = ArgParser(); parser.addOption('username', mandatory: true); - throwsFormat(parser, []); + var results = parser.parse([]); + expect(() => results['username'], throwsA(isA())); }); test('throw if no mandatory args', () { var parser = ArgParser(); parser.addOption('test'); parser.addOption('username', mandatory: true); - throwsFormat(parser, ['--test', 'test']); + var results = parser.parse(['--test', 'test']); + expect(results['test'], equals('test')); + expect(() => results['username'], throwsA(isA())); }); test('parse successfully', () { @@ -530,6 +533,15 @@ void main() { var results = parser.parse(['--test', 'test']); expect(results['test'], equals('test')); }); + + test('throws when value retrieved', () { + var parser = ArgParser(); + parser.addFlag('help', abbr: 'h', negatable: false); + parser.addOption('test', mandatory: true); + var results = parser.parse(['-h']); + expect(results['help'], true); + expect(() => results['test'], throwsA(isA())); + }); }); });