Skip to content

Commit 80bf37c

Browse files
committed
Merge pull request seaneagan#104 from seaneagan/explicit_option_name
Fix seaneagan#91
2 parents 7026a58 + e65792c commit 80bf37c

File tree

12 files changed

+106
-55
lines changed

12 files changed

+106
-55
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
## Unreleased
2+
3+
- Add `name` parameter to `Option` and `Flag` ( #102 )
4+
5+
## 0.6.1
6+
7+
- Allow dynamic help content
8+
19
## 0.6.0
210

311
- Deprecated `declare` in favor of `new Script`.

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,12 @@ main(arguments) => new Script(greet).execute(arguments);
2727
greet(
2828
@Rest(help: 'Name(s) to greet.')
2929
List<String> who, {
30-
@Option(help: 'Alternate word to greet with e.g. "Hi".')
31-
String salutation : 'Hello',
3230
@Option(help: 'How many !\'s to append.')
3331
int enthusiasm : 0,
3432
@Flag(abbr: 'l', help: 'Put names on separate lines.')
35-
bool lineMode : false
33+
bool lineMode : false,
34+
@Option(name: 'greeting', help: 'Alternate word to greet with e.g. "Hi".')
35+
String salutation : 'Hello'
3636
}) {
3737
3838
print(salutation +
@@ -46,7 +46,7 @@ We can call this script as follows:
4646
```shell
4747
$ greet.dart Bob
4848
Hello Bob
49-
$ greet.dart --salutation Hi --enthusiasm 3 -l Alice Bob
49+
$ greet.dart --enthusiasm 3 -l --greeting Hi Alice Bob
5050
Hi
5151
Alice,
5252
Bob!!!

example/greet.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@ main(arguments) => new Script(greet).execute(arguments);
1010
greet(
1111
@Rest(valueHelp: 'who', help: 'Name(s) to greet.')
1212
List<String> who, {
13-
@Option(valueHelp: 'greeting', help: 'Alternate <greeting> to greet with e.g. "Hi".')
14-
String salutation : 'Hello',
1513
@Option(help: 'How many !\'s to append.')
1614
int enthusiasm : 0,
1715
@Flag(abbr: 'l', help: 'Put names on separate lines.')
18-
bool lineMode : false
16+
bool lineMode : false,
17+
@Option(name: 'greeting', help: 'Alternate word to greet with e.g. "Hi".')
18+
String salutation : 'Hello'
1919
}) {
2020

2121
print(salutation +

lib/src/annotations.dart

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@ class Option extends HelpAnnotation {
1919
/// value into a form accepted by the [Script]. It should throw to indicate
2020
/// that the argument is invalid.
2121
final Function parser;
22-
/// A function which validates and/or transforms the raw command-line String
22+
/// A short label or description of the option's value.
2323
final String valueHelp;
24+
/// The non-abbreviated name used to identify the option on the command-line.
25+
final String name;
2426

2527
const Option({
2628
help,
@@ -30,7 +32,8 @@ class Option extends HelpAnnotation {
3032
this.allowMultiple,
3133
this.hide,
3234
this.defaultsTo,
33-
this.valueHelp})
35+
this.valueHelp,
36+
this.name})
3437
: this.parser = parser,
3538
super(help: help);
3639
}
@@ -51,9 +54,10 @@ class Flag extends Option {
5154
defaultsTo,
5255
bool hide,
5356
bool negatable,
54-
String metaName})
57+
String valueHelp,
58+
String name})
5559
: this.negatable = negatable == null ? false : negatable,
56-
super(help: help, abbr: abbr, defaultsTo: defaultsTo, hide: hide, valueHelp: metaName);
60+
super(help: help, abbr: abbr, defaultsTo: defaultsTo, hide: hide, valueHelp: valueHelp, name: name);
5761
}
5862

5963
/// An annotation which gives example arguments that can be passed to a

lib/src/plugins/completion/completion.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,8 @@ class CompletionOptionAdapter extends CompletionAdapter {
134134
CompletionOptionAdapter() : super._();
135135

136136
updateUsage(Usage usage) {
137-
usage.addOption(_COMPLETION, new Option(
137+
usage.addOption(new Option(
138+
name: _COMPLETION,
138139
allowed: _installationNamesHelp,
139140
help: 'Tab completion for this command.'));
140141
}

lib/src/plugins/help/help.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ class Help extends Plugin {
2828
usage.commands.values.forEach(updateUsage);
2929

3030
if(!usage.options.containsKey(_HELP)) {
31-
usage.addOption(_HELP, new Flag(
31+
usage.addOption(new Flag(
32+
name: _HELP,
3233
abbr: 'h',
3334
help: 'Print this usage information.',
3435
negatable: false));

lib/src/script_impl.dart

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ abstract class DeclarationScript extends ScriptImpl {
6464

6565
MethodMirror get _method;
6666

67+
final Map<Usage, Map<String, String>> usageOptionParameterMap = {};
68+
6769
List<Plugin> get plugins {
6870
if(_plugins == null) {
6971
_plugins = [];
@@ -90,7 +92,7 @@ abstract class DeclarationScript extends ScriptImpl {
9092

9193
Usage get usage {
9294
if(_usage == null) {
93-
_usage = getUsageFromFunction(_method);
95+
_usage = getUsageFromFunction(_method, this);
9496
plugins.forEach((plugin) => plugin.updateUsage(_usage));
9597
}
9698
return _usage;
@@ -99,7 +101,7 @@ abstract class DeclarationScript extends ScriptImpl {
99101

100102
_handleResults(CommandInvocation commandInvocation, bool isWindows) {
101103

102-
var topInvocation = convertCommandInvocationToInvocation(commandInvocation, _method);
104+
var topInvocation = convertCommandInvocationToInvocation(commandInvocation, _method, usageOptionParameterMap[usage]);
103105

104106
var topResult = _getTopCommandResult(topInvocation);
105107

@@ -131,10 +133,11 @@ abstract class DeclarationScript extends ScriptImpl {
131133
var classMirror = result.type;
132134
var methods = classMirror.instanceMembers;
133135
var commandMethod = methods[commandSymbol];
134-
var invocation = convertCommandInvocationToInvocation(commandInvocation, commandMethod, memberName: commandSymbol);
135-
var subResult = result.delegate(invocation);
136136
Usage subUsage;
137-
if (commandInvocation.subCommand != null) subUsage = usage.commands[commandInvocation.subCommand.name];
137+
subUsage = usage.commands[commandInvocation.name];
138+
var optionParameterMap = subUsage != null ? usageOptionParameterMap[subUsage] : {};
139+
var invocation = convertCommandInvocationToInvocation(commandInvocation, commandMethod, optionParameterMap, memberName: commandSymbol);
140+
var subResult = result.delegate(invocation);
138141
return _handleSubCommands(reflect(subResult), commandInvocation.subCommand, subUsage, isWindows);
139142
}
140143

@@ -172,3 +175,4 @@ class ClassScript extends DeclarationScript {
172175
invocation.positionalArguments,
173176
invocation.namedArguments);
174177
}
178+

lib/src/usage.dart

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,12 @@ class Usage {
7777
}
7878
return _optionsView;
7979
}
80-
addOption(String name, Option option) {
81-
addOptionToParser(parser, name, option);
82-
_options[name] = option;
80+
addOption(Option option) {
81+
if (option.name == null) {
82+
throw new ArgumentError('option.name cannot be null');
83+
}
84+
addOptionToParser(parser, option);
85+
_options[option.name] = option;
8386
}
8487

8588
List<String> _commandPath;

lib/src/util.dart

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import 'package:collection/iterable_zip.dart';
1010
import 'package:mockable_filesystem/filesystem.dart' as filesystem;
1111

1212
import '../unscripted.dart';
13+
import 'script_impl.dart';
1314
import 'string_codecs.dart';
1415
import 'usage.dart';
1516
import 'invocation_maker.dart';
@@ -79,9 +80,10 @@ getDefaultPositionalName(Symbol symbol) {
7980
// return MirrorSystem.getName(symbol).toUpperCase();
8081
}
8182

82-
Usage getUsageFromFunction(MethodMirror methodMirror, {Usage usage}) {
83+
Usage getUsageFromFunction(MethodMirror methodMirror, DeclarationScript script, {Usage usage}) {
8384

8485
if(usage == null) usage = new Usage();
86+
script.usageOptionParameterMap[usage] = {};
8587

8688
usage.rest = getRestFromMethod(methodMirror);
8789

@@ -160,23 +162,26 @@ Usage getUsageFromFunction(MethodMirror methodMirror, {Usage usage}) {
160162
defaultValue = parameter.defaultValue.reflectee;
161163
}
162164

165+
var optionName = dashesToCamelCase.decode(option.name != null
166+
? option.name : parameterName);
167+
163168
// Update option with any configuration detected in the parameter.
164169
// TODO: This is not very maintainable.
165170
// Use reflection instead to copy values over?
166171
option = option is Flag ?
167172
new Flag(help: option.help, abbr: option.abbr, hide: option.hide,
168-
defaultsTo: defaultValue, negatable: option.negatable) :
173+
defaultsTo: defaultValue, negatable: option.negatable,
174+
name: optionName) :
169175
new Option(help: option.help, abbr: option.abbr,
170176
defaultsTo: defaultValue, allowed: option.allowed,
171177
allowMultiple: allowMultiple, hide: option.hide,
172-
valueHelp: option.valueHelp, parser: parser);
173-
174-
var optionName = dashesToCamelCase.decode(parameterName);
178+
valueHelp: option.valueHelp, parser: parser, name: optionName);
175179

176-
usage.addOption(optionName, option);
180+
script.usageOptionParameterMap[usage][optionName] = parameterName;
181+
usage.addOption(option);
177182
});
178183

179-
_addSubCommandsForClass(usage, methodMirror.returnType);
184+
_addSubCommandsForClass(usage, script, methodMirror.returnType);
180185

181186
return usage;
182187
}
@@ -190,7 +195,7 @@ getParserFromType(TypeMirror typeMirror) {
190195
return null;
191196
}
192197

193-
_addSubCommandsForClass(Usage usage, TypeMirror typeMirror) {
198+
_addSubCommandsForClass(Usage usage, DeclarationScript script, TypeMirror typeMirror) {
194199
if(typeMirror is ClassMirror) {
195200

196201
var methods = typeMirror.instanceMembers.values;
@@ -214,6 +219,7 @@ _addSubCommandsForClass(Usage usage, TypeMirror typeMirror) {
214219
.decode(MirrorSystem.getName(methodMirror.simpleName));
215220
getUsageFromFunction(
216221
methodMirror,
222+
script,
217223
usage: usage.addCommand(commandName, subCommand));
218224
});
219225
}
@@ -241,7 +247,7 @@ getFirstMetadataMatch(DeclarationMirror declaration, bool match(metadata)) {
241247
.firstWhere(match, orElse: () => null);
242248
}
243249

244-
void addOptionToParser(ArgParser parser, String name, Option option) {
250+
void addOptionToParser(ArgParser parser, Option option) {
245251

246252
var suffix;
247253

@@ -282,7 +288,7 @@ void addOptionToParser(ArgParser parser, String name, Option option) {
282288

283289
var parserMethod = 'add$suffix';
284290

285-
reflect(parser).invoke(new Symbol(parserMethod), [name], namedParameters);
291+
reflect(parser).invoke(new Symbol(parserMethod), [option.name], namedParameters);
286292
}
287293

288294
// Returns a List whose elements are the required argument count, and whether
@@ -329,18 +335,20 @@ MethodMirror getUnnamedConstructor(ClassMirror classMirror) {
329335
constructor.constructorName == const Symbol(''), orElse: () => null);
330336
}
331337

332-
convertCommandInvocationToInvocation(CommandInvocation commandInvocation, MethodMirror method, {Symbol memberName: #call}) {
338+
convertCommandInvocationToInvocation(CommandInvocation commandInvocation, MethodMirror method, Map<String, String> optionParameterMap, {Symbol memberName: #call}) {
333339

334340
var positionals = commandInvocation.positionals;
335341

336342
var named = {};
337343

338344
commandInvocation.options.forEach((option, value) {
339-
var paramSymbol = new Symbol(dashesToCamelCase.encode(option));
345+
var paramSymbol = new Symbol(optionParameterMap[option]);
340346
var paramExists = method.parameters.any((param) =>
341347
param.simpleName == paramSymbol);
342-
if(paramExists) {
348+
if (paramExists) {
343349
named[paramSymbol] = value;
350+
} else {
351+
// print('Param "${optionParameterMap[option]}" does not exist for option "$option"');
344352
}
345353
});
346354

test/foo.txt

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)