Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 library options; | 1 library options; |
| 2 | 2 |
| 3 import 'package:collection/wrappers.dart'; | 3 import 'package:collection/wrappers.dart'; |
| 4 | 4 |
| 5 /// A command-line option. Includes both flags and options which take a value. | 5 /// A command-line option. Includes both flags and options which take a value. |
| 6 class Option { | 6 class Option { |
| 7 final String name; | 7 final String name; |
| 8 final String abbreviation; | 8 final String abbreviation; |
| 9 final List<String> allowed; | 9 final List<String> allowed; |
| 10 final defaultValue; | 10 final defaultValue; |
| 11 final Function callback; | 11 final Function callback; |
| 12 final String help; | 12 final String help; |
| 13 final String valueHelp; | 13 final String valueHelp; |
| 14 final Map<String, String> allowedHelp; | 14 final Map<String, String> allowedHelp; |
| 15 final bool isFlag; | 15 final OptionType type; |
| 16 final bool negatable; | 16 final bool negatable; |
| 17 final bool allowMultiple; | |
| 18 final bool hide; | 17 final bool hide; |
| 19 | 18 |
| 19 /// Whether the option is boolean-valued flag. | |
| 20 bool get isFlag => type == OptionType.FLAG; | |
| 21 | |
| 22 /// Whether the option takes a single value. | |
| 23 bool get isSingle => type == OptionType.SINGLE; | |
| 24 | |
| 25 /// Whether the option allows multiple values. | |
| 26 bool get isMultiple => type == OptionType.MULTIPLE; | |
| 27 | |
| 20 Option(this.name, this.abbreviation, this.help, this.valueHelp, | 28 Option(this.name, this.abbreviation, this.help, this.valueHelp, |
| 21 List<String> allowed, Map<String, String> allowedHelp, this.defaultValue, | 29 List<String> allowed, Map<String, String> allowedHelp, this.defaultValue, |
| 22 this.callback, {this.isFlag, this.negatable, this.allowMultiple: false, | 30 this.callback, this.type, {this.negatable, this.hide: false}) : |
| 23 this.hide: false}) : | |
| 24 this.allowed = allowed == null ? | 31 this.allowed = allowed == null ? |
| 25 null : new UnmodifiableListView(allowed), | 32 null : new UnmodifiableListView(allowed), |
| 26 this.allowedHelp = allowedHelp == null ? | 33 this.allowedHelp = allowedHelp == null ? |
| 27 null : new UnmodifiableMapView(allowedHelp) { | 34 null : new UnmodifiableMapView(allowedHelp) { |
| 28 | 35 |
| 29 if (name.isEmpty) { | 36 if (name.isEmpty) { |
| 30 throw new ArgumentError('Name cannot be empty.'); | 37 throw new ArgumentError('Name cannot be empty.'); |
| 31 } else if (name.startsWith('-')) { | 38 } else if (name.startsWith('-')) { |
| 32 throw new ArgumentError('Name $name cannot start with "-".'); | 39 throw new ArgumentError('Name $name cannot start with "-".'); |
| 33 } | 40 } |
| 34 | 41 |
| 35 // Ensure name does not contain any invalid characters. | 42 // Ensure name does not contain any invalid characters. |
| 36 if (_invalidChars.hasMatch(name)) { | 43 if (_invalidChars.hasMatch(name)) { |
| 37 throw new ArgumentError('Name "$name" contains invalid characters.'); | 44 throw new ArgumentError('Name "$name" contains invalid characters.'); |
| 38 } | 45 } |
| 39 | 46 |
| 40 if (abbreviation != null) { | 47 if (abbreviation != null) { |
| 41 if (abbreviation.length != 1) { | 48 if (abbreviation.length != 1) { |
| 42 throw new ArgumentError('Abbreviation must be null or have length 1.'); | 49 throw new ArgumentError('Abbreviation must be null or have length 1.'); |
| 43 } else if(abbreviation == '-') { | 50 } else if(abbreviation == '-') { |
| 44 throw new ArgumentError('Abbreviation cannot be "-".'); | 51 throw new ArgumentError('Abbreviation cannot be "-".'); |
| 45 } | 52 } |
| 46 | 53 |
| 47 if (_invalidChars.hasMatch(abbreviation)) { | 54 if (_invalidChars.hasMatch(abbreviation)) { |
| 48 throw new ArgumentError('Abbreviation is an invalid character.'); | 55 throw new ArgumentError('Abbreviation is an invalid character.'); |
| 49 } | 56 } |
| 50 } | 57 } |
| 51 } | 58 } |
| 52 | 59 |
| 60 /// Returns [value] if non-`null`, otherwise returns the default value for | |
| 61 /// this option. | |
| 62 /// | |
| 63 /// For single-valued options, it will be [defaultValue] if set or `null` | |
| 64 /// otherwise. For multiple-valued options, it will be an empty list or a | |
| 65 /// list containing [defaultValue] if set. | |
| 66 dynamic getOrDefault(value) { | |
| 67 if (value != null) return value; | |
| 68 | |
| 69 if (!isMultiple) return defaultValue; | |
| 70 if (defaultValue != null) return [defaultValue]; | |
| 71 return []; | |
| 72 } | |
| 73 | |
| 53 static final _invalidChars = new RegExp(r'''[ \t\r\n"'\\/]'''); | 74 static final _invalidChars = new RegExp(r'''[ \t\r\n"'\\/]'''); |
| 54 } | 75 } |
| 76 | |
| 77 /// What kinds of values an option accepts. | |
| 78 class OptionType { | |
| 79 /// An option that can only be `true` or `false`. | |
| 80 /// | |
| 81 /// The presence of the option name itself in the argument list means `true`. | |
| 82 static const FLAG = const OptionType("OptionType.FLAG"); | |
| 83 | |
| 84 /// An option that takes a single value. | |
| 85 /// | |
| 86 /// Examples: | |
| 87 /// | |
| 88 /// --mode debug | |
| 89 /// -mdebug | |
| 90 /// --mode=debug | |
| 91 /// | |
| 92 /// If the option is passed more than once, the last one wins. | |
| 93 static const SINGLE = const OptionType("OptionType.SINGLE"); | |
| 94 | |
| 95 /// An option that allows multiple values. | |
| 96 /// | |
| 97 /// Example: | |
| 98 /// | |
| 99 /// --output text --output xml | |
| 100 /// | |
| 101 /// In the parsed [ArgResults], a multiple-valued option will always return | |
| 102 /// a list, even if one or no values were passed. | |
| 103 static const MULTIPLE = const OptionType("OptionType.MULTIPLE"); | |
| 104 | |
| 105 const OptionType(this.name); | |
|
nweiz
2014/07/14 21:22:34
This should be private.
Bob Nystrom
2014/07/15 21:05:23
Done.
| |
| 106 | |
| 107 final String name; | |
|
nweiz
2014/07/14 21:22:34
Nit: fields go above constructors.
Bob Nystrom
2014/07/15 21:05:23
Done.
| |
| 108 } | |
| OLD | NEW |