1
0
Fork 0
mirror of https://github.com/jashkenas/coffeescript.git synced 2022-11-09 12:23:24 -05:00

OptionParser and related tests needed a cleanup

The object returned from OptionParser::parse no longer has a `literals`
property. It was pretty arbitrary, anyway.
This commit is contained in:
Michael Ficarra 2012-01-25 19:47:03 -05:00
parent eb5c4057a1
commit c0dac45fe1
5 changed files with 80 additions and 68 deletions

View file

@ -43,7 +43,7 @@
optionParser = null; optionParser = null;
exports.run = function() { exports.run = function() {
var source, _i, _len, _results; var literals, source, _i, _len, _results;
parseOptions(); parseOptions();
if (opts.nodejs) return forkNode(); if (opts.nodejs) return forkNode();
if (opts.help) return usage(); if (opts.help) return usage();
@ -56,8 +56,8 @@
if (opts.stdio) return compileStdio(); if (opts.stdio) return compileStdio();
if (opts["eval"]) return compileScript(null, sources[0]); if (opts["eval"]) return compileScript(null, sources[0]);
if (!sources.length) return require('./repl'); if (!sources.length) return require('./repl');
if (opts.run) opts.literals = sources.splice(1).concat(opts.literals); literals = opts.run ? sources.splice(1) : [];
process.argv = process.argv.slice(0, 2).concat(opts.literals); process.argv = process.argv.slice(0, 2).concat(literals);
process.argv[0] = 'coffee'; process.argv[0] = 'coffee';
process.execPath = require.main.filename; process.execPath = require.main.filename;
_results = []; _results = [];

View file

@ -12,10 +12,9 @@
} }
OptionParser.prototype.parse = function(args) { OptionParser.prototype.parse = function(args) {
var arg, i, isOption, matchedRule, options, originalArgs, pos, rule, skippingArgument, value, _i, _j, _len, _len2, _ref; var arg, i, isOption, matchedRule, options, originalArgs, pos, rule, seenNonOptionArg, skippingArgument, value, _i, _j, _len, _len2, _ref;
options = { options = {
"arguments": [], "arguments": []
literals: []
}; };
skippingArgument = false; skippingArgument = false;
originalArgs = args; originalArgs = args;
@ -28,29 +27,32 @@
} }
if (arg === '--') { if (arg === '--') {
pos = originalArgs.indexOf('--'); pos = originalArgs.indexOf('--');
options["arguments"] = [originalArgs[1 + pos]]; options["arguments"] = options["arguments"].concat(originalArgs.slice(pos + 1));
options.literals = originalArgs.slice(2 + pos);
break; break;
} }
isOption = !!(arg.match(LONG_FLAG) || arg.match(SHORT_FLAG)); isOption = !!(arg.match(LONG_FLAG) || arg.match(SHORT_FLAG));
matchedRule = false; seenNonOptionArg = options["arguments"].length > 0;
_ref = this.rules; if (!seenNonOptionArg) {
for (_j = 0, _len2 = _ref.length; _j < _len2; _j++) { matchedRule = false;
rule = _ref[_j]; _ref = this.rules;
if (rule.shortFlag === arg || rule.longFlag === arg) { for (_j = 0, _len2 = _ref.length; _j < _len2; _j++) {
value = rule.hasArgument ? (skippingArgument = true, args[i + 1]) : true; rule = _ref[_j];
options[rule.name] = rule.isList ? (options[rule.name] || []).concat(value) : value; if (rule.shortFlag === arg || rule.longFlag === arg) {
matchedRule = true; value = true;
break; if (rule.hasArgument) {
skippingArgument = true;
value = args[i + 1];
}
options[rule.name] = rule.isList ? (options[rule.name] || []).concat(value) : value;
matchedRule = true;
break;
}
}
if (isOption && !matchedRule) {
throw new Error("unrecognized option: " + arg);
} }
} }
if (isOption && !matchedRule) { if (seenNonOptionArg || !isOption) options["arguments"].push(arg);
throw new Error("unrecognized option: " + arg);
}
if (!isOption) {
options["arguments"] = originalArgs.slice(originalArgs.indexOf(arg));
break;
}
} }
return options; return options;
}; };
@ -74,9 +76,9 @@
})(); })();
LONG_FLAG = /^(--\w[\w\-]+)/; LONG_FLAG = /^(--\w[\w\-]*)/;
SHORT_FLAG = /^(-\w)/; SHORT_FLAG = /^(-\w)$/;
MULTI_FLAG = /^-(\w{2,})/; MULTI_FLAG = /^-(\w{2,})/;

View file

@ -69,9 +69,8 @@ exports.run = ->
return compileStdio() if opts.stdio return compileStdio() if opts.stdio
return compileScript null, sources[0] if opts.eval return compileScript null, sources[0] if opts.eval
return require './repl' unless sources.length return require './repl' unless sources.length
if opts.run literals = if opts.run then sources.splice 1 else []
opts.literals = sources.splice(1).concat opts.literals process.argv = process.argv[0..1].concat literals
process.argv = process.argv[0..1].concat opts.literals
process.argv[0] = 'coffee' process.argv[0] = 'coffee'
process.execPath = require.main.filename process.execPath = require.main.filename
for source in sources for source in sources

View file

@ -17,14 +17,13 @@ exports.OptionParser = class OptionParser
@rules = buildRules rules @rules = buildRules rules
# Parse the list of arguments, populating an `options` object with all of the # Parse the list of arguments, populating an `options` object with all of the
# specified options, and return it. `options.arguments` will be an array # specified options, and return it. Options after the first non-option
# containing the remaining non-option arguments. `options.literals` will be # argument are treated as arguments. `options.arguments` will be an array
# an array of options that are meant to be passed through directly to the # containing the remaining arguments. This is a simpler API than many option
# executing script. This is a simpler API than many option parsers that allow # parsers that allow you to attach callback actions for every flag. Instead,
# you to attach callback actions for every flag. Instead, you're responsible # you're responsible for interpreting the options object.
# for interpreting the options object.
parse: (args) -> parse: (args) ->
options = arguments: [], literals: [] options = arguments: []
skippingArgument = no skippingArgument = no
originalArgs = args originalArgs = args
args = normalizeArguments args args = normalizeArguments args
@ -34,25 +33,26 @@ exports.OptionParser = class OptionParser
continue continue
if arg is '--' if arg is '--'
pos = originalArgs.indexOf '--' pos = originalArgs.indexOf '--'
options.arguments = [originalArgs[1 + pos]] options.arguments = options.arguments.concat originalArgs[(pos + 1)..]
options.literals = originalArgs[(2 + pos)..]
break break
isOption = !!(arg.match(LONG_FLAG) or arg.match(SHORT_FLAG)) isOption = !!(arg.match(LONG_FLAG) or arg.match(SHORT_FLAG))
matchedRule = no # the CS option parser is a little odd; options after the first
for rule in @rules # non-option argument are treated as non-option arguments themselves
if rule.shortFlag is arg or rule.longFlag is arg seenNonOptionArg = options.arguments.length > 0
value = if rule.hasArgument unless seenNonOptionArg
skippingArgument = yes matchedRule = no
args[i + 1] for rule in @rules
else if rule.shortFlag is arg or rule.longFlag is arg
true value = true
options[rule.name] = if rule.isList then (options[rule.name] or []).concat value else value if rule.hasArgument
matchedRule = yes skippingArgument = yes
break value = args[i + 1]
throw new Error "unrecognized option: #{arg}" if isOption and not matchedRule options[rule.name] = if rule.isList then (options[rule.name] or []).concat value else value
if not isOption matchedRule = yes
options.arguments = originalArgs[(originalArgs.indexOf arg)..] break
break throw new Error "unrecognized option: #{arg}" if isOption and not matchedRule
if seenNonOptionArg or not isOption
options.arguments.push arg
options options
# Return the help text for this **OptionParser**, listing and describing all # Return the help text for this **OptionParser**, listing and describing all
@ -71,8 +71,8 @@ exports.OptionParser = class OptionParser
# ------- # -------
# Regex matchers for option flags. # Regex matchers for option flags.
LONG_FLAG = /^(--\w[\w\-]+)/ LONG_FLAG = /^(--\w[\w\-]*)/
SHORT_FLAG = /^(-\w)/ SHORT_FLAG = /^(-\w)$/
MULTI_FLAG = /^-(\w{2,})/ MULTI_FLAG = /^-(\w{2,})/
OPTIONAL = /\[(\w+(\*?))\]/ OPTIONAL = /\[(\w+(\*?))\]/

View file

@ -13,20 +13,31 @@ opt = new OptionParser [
['-l', '--list [FILES*]', 'desc list'] ['-l', '--list [FILES*]', 'desc list']
] ]
result = opt.parse ['one', 'two', 'three', '-r', 'dir'] test "basic arguments", ->
args = ['one', 'two', 'three', '-r', 'dir']
result = opt.parse args
arrayEq args, result.arguments
eq undefined, result.required
eq 5, result.arguments.length test "boolean and parameterised options", ->
eq '-r', result.arguments[3] result = opt.parse ['--optional', '-r', 'folder', 'one', 'two']
ok result.optional
eq 'folder', result.required
arrayEq ['one', 'two'], result.arguments
result = opt.parse ['--optional', '-r', 'folder', 'one', 'two'] test "list options", ->
result = opt.parse ['-l', 'one.txt', '-l', 'two.txt', 'three']
arrayEq ['one.txt', 'two.txt'], result.list
arrayEq ['three'], result.arguments
ok result.optional test "-- and interesting combinations", ->
eq 'folder', result.required result = opt.parse ['-o','-r','a','-r','b','-o','--','-a','b','--c','d']
eq 'one two', result.arguments.join ' ' arrayEq ['-a', 'b', '--c', 'd'], result.arguments
ok result.optional
result = opt.parse ['-l', 'one.txt', '-l', 'two.txt', 'three'] eq 'b', result.required
ok result.list instanceof Array
ok result.list.join(' ') is 'one.txt two.txt'
ok result.arguments.join(' ') is 'three'
args = ['--','-o','a','-r','c','-o','--','-a','arg0','-b','arg1']
result = opt.parse args
eq undefined, result.optional
eq undefined, result.required
arrayEq args[1..], result.arguments