OLD | NEW |
| (Empty) |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 library args.src.option; | |
6 | |
7 import 'dart:collection'; | |
8 | |
9 /// Creates a new [Option]. | |
10 /// | |
11 /// Since [Option] doesn't have a public constructor, this lets [ArgParser] | |
12 /// get to it. This function isn't exported to the public API of the package. | |
13 Option newOption(String name, String abbreviation, String help, | |
14 String valueHelp, List<String> allowed, Map<String, String> allowedHelp, | |
15 defaultValue, Function callback, OptionType type, | |
16 {bool negatable, bool splitCommas, bool hide: false}) { | |
17 return new Option._(name, abbreviation, help, valueHelp, allowed, allowedHelp, | |
18 defaultValue, callback, type, negatable: negatable, | |
19 splitCommas: splitCommas, hide: hide); | |
20 } | |
21 | |
22 /// A command-line option. Includes both flags and options which take a value. | |
23 class Option { | |
24 final String name; | |
25 final String abbreviation; | |
26 final List<String> allowed; | |
27 final defaultValue; | |
28 final Function callback; | |
29 final String help; | |
30 final String valueHelp; | |
31 final Map<String, String> allowedHelp; | |
32 final OptionType type; | |
33 final bool negatable; | |
34 final bool splitCommas; | |
35 final bool hide; | |
36 | |
37 /// Whether the option is boolean-valued flag. | |
38 bool get isFlag => type == OptionType.FLAG; | |
39 | |
40 /// Whether the option takes a single value. | |
41 bool get isSingle => type == OptionType.SINGLE; | |
42 | |
43 /// Whether the option allows multiple values. | |
44 bool get isMultiple => type == OptionType.MULTIPLE; | |
45 | |
46 Option._(this.name, this.abbreviation, this.help, this.valueHelp, | |
47 List<String> allowed, Map<String, String> allowedHelp, this.defaultValue, | |
48 this.callback, OptionType type, {this.negatable, bool splitCommas, | |
49 this.hide: false}) | |
50 : this.allowed = allowed == null | |
51 ? null | |
52 : new UnmodifiableListView(allowed), | |
53 this.allowedHelp = allowedHelp == null | |
54 ? null | |
55 : new UnmodifiableMapView(allowedHelp), | |
56 this.type = type, | |
57 // If the user doesn't specify [splitCommas], it defaults to true for | |
58 // multiple options. | |
59 this.splitCommas = splitCommas == null | |
60 ? type == OptionType.MULTIPLE | |
61 : splitCommas { | |
62 if (name.isEmpty) { | |
63 throw new ArgumentError('Name cannot be empty.'); | |
64 } else if (name.startsWith('-')) { | |
65 throw new ArgumentError('Name $name cannot start with "-".'); | |
66 } | |
67 | |
68 // Ensure name does not contain any invalid characters. | |
69 if (_invalidChars.hasMatch(name)) { | |
70 throw new ArgumentError('Name "$name" contains invalid characters.'); | |
71 } | |
72 | |
73 if (abbreviation != null) { | |
74 if (abbreviation.length != 1) { | |
75 throw new ArgumentError('Abbreviation must be null or have length 1.'); | |
76 } else if (abbreviation == '-') { | |
77 throw new ArgumentError('Abbreviation cannot be "-".'); | |
78 } | |
79 | |
80 if (_invalidChars.hasMatch(abbreviation)) { | |
81 throw new ArgumentError('Abbreviation is an invalid character.'); | |
82 } | |
83 } | |
84 } | |
85 | |
86 /// Returns [value] if non-`null`, otherwise returns the default value for | |
87 /// this option. | |
88 /// | |
89 /// For single-valued options, it will be [defaultValue] if set or `null` | |
90 /// otherwise. For multiple-valued options, it will be an empty list or a | |
91 /// list containing [defaultValue] if set. | |
92 dynamic getOrDefault(value) { | |
93 if (value != null) return value; | |
94 | |
95 if (!isMultiple) return defaultValue; | |
96 if (defaultValue != null) return [defaultValue]; | |
97 return []; | |
98 } | |
99 | |
100 static final _invalidChars = new RegExp(r'''[ \t\r\n"'\\/]'''); | |
101 } | |
102 | |
103 /// What kinds of values an option accepts. | |
104 class OptionType { | |
105 /// An option that can only be `true` or `false`. | |
106 /// | |
107 /// The presence of the option name itself in the argument list means `true`. | |
108 static const FLAG = const OptionType._("OptionType.FLAG"); | |
109 | |
110 /// An option that takes a single value. | |
111 /// | |
112 /// Examples: | |
113 /// | |
114 /// --mode debug | |
115 /// -mdebug | |
116 /// --mode=debug | |
117 /// | |
118 /// If the option is passed more than once, the last one wins. | |
119 static const SINGLE = const OptionType._("OptionType.SINGLE"); | |
120 | |
121 /// An option that allows multiple values. | |
122 /// | |
123 /// Example: | |
124 /// | |
125 /// --output text --output xml | |
126 /// | |
127 /// In the parsed [ArgResults], a multiple-valued option will always return | |
128 /// a list, even if one or no values were passed. | |
129 static const MULTIPLE = const OptionType._("OptionType.MULTIPLE"); | |
130 | |
131 final String name; | |
132 | |
133 const OptionType._(this.name); | |
134 } | |
OLD | NEW |