mirror of
https://github.com/jashkenas/coffeescript.git
synced 2022-11-09 12:23:24 -05:00
cleaning and shrinking the option parser
This commit is contained in:
parent
fe32146adc
commit
66a6568fe7
2 changed files with 43 additions and 78 deletions
|
@ -1,27 +1,30 @@
|
|||
(function(){
|
||||
var LONG_FLAG, OPTIONAL, SHORT_FLAG, build_rule, build_rules, op, spaces;
|
||||
// Create an OptionParser with a list of valid options.
|
||||
var LONG_FLAG, OPTIONAL, SHORT_FLAG, build_rule, build_rules, op;
|
||||
// Create an OptionParser with a list of valid options, in the form:
|
||||
// [short-flag (optional), long-flag, description]
|
||||
// And an optional banner for the usage help.
|
||||
op = (exports.OptionParser = function OptionParser(rules, banner) {
|
||||
this.banner = banner || 'Usage: [Options]';
|
||||
this.options_title = 'Available options:';
|
||||
this.rules = build_rules(rules);
|
||||
return this;
|
||||
});
|
||||
// Parse the argument array, calling defined callbacks, returning the remaining non-option arguments.
|
||||
// Parse the argument array, populating an options object with all of the
|
||||
// specified options, and returning it. options.arguments will be an array
|
||||
// containing the remaning non-option arguments.
|
||||
op.prototype.parse = function parse(args) {
|
||||
var _a, _b, arg, is_option, options, rule;
|
||||
arguments = Array.prototype.slice.call(arguments, 0);
|
||||
options = {
|
||||
arguments: []
|
||||
};
|
||||
args = args.concat([]);
|
||||
while (((arg = args.shift()))) {
|
||||
args = args.slice(0);
|
||||
while (arg = args.shift()) {
|
||||
is_option = false;
|
||||
_a = this.rules;
|
||||
for (_b = 0; _b < _a.length; _b++) {
|
||||
rule = _a[_b];
|
||||
if (rule.letter === arg || rule.flag === arg) {
|
||||
options[rule.name] = rule.argument ? args.shift() : true;
|
||||
options[rule.name] = rule.has_argument ? args.shift() : true;
|
||||
is_option = true;
|
||||
break;
|
||||
}
|
||||
|
@ -34,31 +37,24 @@
|
|||
};
|
||||
// Return the help text for this OptionParser, for --help and such.
|
||||
op.prototype.help = function help() {
|
||||
var _a, _b, _c, _d, has_shorts, lines, longest, rule, text;
|
||||
longest = 0;
|
||||
has_shorts = false;
|
||||
lines = [this.banner, '', this.options_title];
|
||||
var _a, _b, _c, _d, _e, _f, _g, i, let_part, lines, rule, spaces;
|
||||
lines = [this.banner, '', 'Available options:'];
|
||||
_a = this.rules;
|
||||
for (_b = 0; _b < _a.length; _b++) {
|
||||
rule = _a[_b];
|
||||
if (rule.letter) {
|
||||
has_shorts = true;
|
||||
}
|
||||
if (rule.flag.length > longest) {
|
||||
longest = rule.flag.length;
|
||||
}
|
||||
}
|
||||
_c = this.rules;
|
||||
for (_d = 0; _d < _c.length; _d++) {
|
||||
rule = _c[_d];
|
||||
has_shorts ? (text = rule.letter ? spaces(2) + rule.letter + ', ' : spaces(6)) : null;
|
||||
text += spaces(longest, rule.flag) + spaces(3);
|
||||
text += rule.description;
|
||||
lines.push(text);
|
||||
spaces = 15 - rule.flag.length;
|
||||
spaces = spaces > 0 ? (function() {
|
||||
_c = []; _f = 0; _g = spaces;
|
||||
for (_e = 0, i=_f; (_f <= _g ? i <= _g : i >= _g); (_f <= _g ? i += 1 : i -= 1), _e++) {
|
||||
_c.push(' ');
|
||||
}
|
||||
return _c;
|
||||
}).call(this).join('') : '';
|
||||
let_part = rule.letter ? rule.letter + ', ' : ' ';
|
||||
lines.push(' ' + let_part + rule.flag + spaces + rule.description);
|
||||
}
|
||||
return lines.join('\n');
|
||||
};
|
||||
// Private:
|
||||
// Regex matchers for option flags.
|
||||
LONG_FLAG = /^(--[\w\-]+)/;
|
||||
SHORT_FLAG = /^(-\w+)/;
|
||||
|
@ -89,23 +85,7 @@
|
|||
letter: letter,
|
||||
flag: flag,
|
||||
description: description,
|
||||
argument: !!(match && match[1])
|
||||
has_argument: !!(match && match[1])
|
||||
};
|
||||
};
|
||||
// Space-pad a string with the specified number of characters.
|
||||
spaces = function spaces(num, text) {
|
||||
var builder;
|
||||
builder = [];
|
||||
if (text) {
|
||||
if (text.length >= num) {
|
||||
return text;
|
||||
}
|
||||
num -= text.length;
|
||||
builder.push(text);
|
||||
}
|
||||
while (num -= 1) {
|
||||
builder.push(' ');
|
||||
}
|
||||
return builder.join('');
|
||||
};
|
||||
})();
|
||||
|
|
|
@ -1,19 +1,22 @@
|
|||
# Create an OptionParser with a list of valid options.
|
||||
# Create an OptionParser with a list of valid options, in the form:
|
||||
# [short-flag (optional), long-flag, description]
|
||||
# And an optional banner for the usage help.
|
||||
op: exports.OptionParser: (rules, banner) ->
|
||||
@banner: banner or 'Usage: [Options]'
|
||||
@options_title: 'Available options:'
|
||||
@rules: build_rules(rules)
|
||||
@banner: banner or 'Usage: [Options]'
|
||||
@rules: build_rules(rules)
|
||||
this
|
||||
|
||||
# Parse the argument array, calling defined callbacks, returning the remaining non-option arguments.
|
||||
# Parse the argument array, populating an options object with all of the
|
||||
# specified options, and returning it. options.arguments will be an array
|
||||
# containing the remaning non-option arguments.
|
||||
op::parse: (args) ->
|
||||
options: {arguments: []}
|
||||
args: args.concat []
|
||||
while (arg: args.shift())
|
||||
args: args.slice 0
|
||||
while arg: args.shift()
|
||||
is_option: false
|
||||
for rule in @rules
|
||||
if rule.letter is arg or rule.flag is arg
|
||||
options[rule.name]: if rule.argument then args.shift() else true
|
||||
options[rule.name]: if rule.has_argument then args.shift() else true
|
||||
is_option: true
|
||||
break
|
||||
options.arguments.push arg unless is_option
|
||||
|
@ -21,22 +24,14 @@ op::parse: (args) ->
|
|||
|
||||
# Return the help text for this OptionParser, for --help and such.
|
||||
op::help: ->
|
||||
longest: 0
|
||||
has_shorts: false
|
||||
lines: [@banner, '', @options_title]
|
||||
lines: [@banner, '', 'Available options:']
|
||||
for rule in @rules
|
||||
has_shorts: true if rule.letter
|
||||
longest: rule.flag.length if rule.flag.length > longest
|
||||
for rule in @rules
|
||||
if has_shorts
|
||||
text: if rule.letter then spaces(2) + rule.letter + ', ' else spaces(6)
|
||||
text += spaces(longest, rule.flag) + spaces(3)
|
||||
text += rule.description
|
||||
lines.push text
|
||||
spaces: 15 - rule.flag.length
|
||||
spaces: if spaces > 0 then (' ' for i in [0..spaces]).join('') else ''
|
||||
let_part: if rule.letter then rule.letter + ', ' else ' '
|
||||
lines.push ' ' + let_part + rule.flag + spaces + rule.description
|
||||
lines.join('\n')
|
||||
|
||||
# Private:
|
||||
|
||||
# Regex matchers for option flags.
|
||||
LONG_FLAG: /^(--[\w\-]+)/
|
||||
SHORT_FLAG: /^(-\w+)/
|
||||
|
@ -46,27 +41,17 @@ OPTIONAL: /\[(.+)\]/
|
|||
# [letter-flag, long-flag, help], or [long-flag, help].
|
||||
build_rules: (rules) ->
|
||||
for tuple in rules
|
||||
tuple.unshift(null) if tuple.length < 3
|
||||
build_rule(tuple...)
|
||||
tuple.unshift null if tuple.length < 3
|
||||
build_rule tuple...
|
||||
|
||||
# Build a rule from a short-letter-flag, long-form-flag, and help text.
|
||||
build_rule: (letter, flag, description) ->
|
||||
match: flag.match(OPTIONAL)
|
||||
flag: flag.match(LONG_FLAG)[1]
|
||||
{
|
||||
name: flag.substr(2)
|
||||
name: flag.substr 2
|
||||
letter: letter
|
||||
flag: flag
|
||||
description: description
|
||||
argument: !!(match and match[1])
|
||||
has_argument: !!(match and match[1])
|
||||
}
|
||||
|
||||
# Space-pad a string with the specified number of characters.
|
||||
spaces: (num, text) ->
|
||||
builder: []
|
||||
if text
|
||||
return text if text.length >= num
|
||||
num -= text.length
|
||||
builder.push text
|
||||
while num -= 1 then builder.push ' '
|
||||
builder.join ''
|
||||
|
|
Loading…
Reference in a new issue