From 53abcbeff11e3f2ab60cf6fe617fca781c5b7e76 Mon Sep 17 00:00:00 2001 From: mdevils Date: Fri, 22 Aug 2014 21:06:39 +0400 Subject: [PATCH] Fix for multiple argument values --- docopt.coffee | 25 +++++++++++++-- docopt.js | 76 +++++++++++++++++++++++++++++----------------- test_docopt.coffee | 16 +++++++++- 3 files changed, 86 insertions(+), 31 deletions(-) diff --git a/docopt.coffee b/docopt.coffee index fde90f4..789095b 100644 --- a/docopt.coffee +++ b/docopt.coffee @@ -35,6 +35,7 @@ class Pattern fix: -> @fix_identities() @fix_list_arguments() + @fix_list_options() fix_identities: (uniq=null) -> """Make pattern-tree tips point to same object if they are equal.""" @@ -64,6 +65,17 @@ class Pattern when counts[e] > 1 and e.constructor is Argument @ + fix_list_options: -> + """Find options that should accumulate values and fix them.""" + either = (c.children for c in @either().children) + for child in either + counts = {} + for c in child + counts[c] = (counts[c] ? 0) + 1 + e.value = [] for e in child \ + when counts[e] > 1 and e.constructor is Option + @ + either: -> if not @hasOwnProperty 'children' return new Either [new Required [@]] @@ -182,8 +194,17 @@ class Option extends Pattern new Option short, long, argcount, value match: (left, collected=[]) -> - left_ = (l for l in left when (l.constructor isnt Option \ - or @short isnt l.short or @long isnt l.long)) + left_ = [] + values = [] + for l in left + if l.constructor is Option and @short is l.short and @long is l.long + values.push l.value + else + left_.push l + if @value.constructor is Array + console.log JSON.stringify [@, left] + @value = @value.concat(values) + collected.push @ [left.join(', ') isnt left_.join(', '), left_, collected] class AnyOptions extends Pattern diff --git a/docopt.js b/docopt.js index fdd0585..453a6d1 100644 --- a/docopt.js +++ b/docopt.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.3.3 +// Generated by CoffeeScript 1.7.1 (function() { var AnyOptions, Argument, Command, Dict, DocoptExit, DocoptLanguageError, Either, OneOrMore, Option, Optional, Pattern, Required, TokenStream, docopt, extras, formal_usage, parse_args, parse_atom, parse_doc_options, parse_expr, parse_long, parse_pattern, parse_seq, parse_shorts, print, printable_usage, __hasProp = {}.hasOwnProperty, @@ -10,7 +10,6 @@ }; DocoptLanguageError = (function(_super) { - __extends(DocoptLanguageError, _super); function DocoptLanguageError(message) { @@ -23,7 +22,6 @@ })(Error); DocoptExit = (function(_super) { - __extends(DocoptExit, _super); function DocoptExit(message) { @@ -39,7 +37,6 @@ })(Error); Pattern = (function() { - function Pattern(children) { this.children = children != null ? children : []; } @@ -72,7 +69,8 @@ Pattern.prototype.fix = function() { this.fix_identities(); - return this.fix_list_arguments(); + this.fix_list_arguments(); + return this.fix_list_options(); }; Pattern.prototype.fix_identities = function(uniq) { @@ -81,7 +79,6 @@ uniq = null; } "Make pattern-tree tips point to same object if they are equal."; - if (!this.hasOwnProperty('children')) { return this; } @@ -116,7 +113,6 @@ Pattern.prototype.fix_list_arguments = function() { "Find arguments that should accumulate values and fix them."; - var c, child, counts, e, either, _i, _j, _k, _len, _len1, _len2, _ref; either = (function() { var _i, _len, _ref, _results; @@ -145,6 +141,36 @@ return this; }; + Pattern.prototype.fix_list_options = function() { + "Find options that should accumulate values and fix them."; + var c, child, counts, e, either, _i, _j, _k, _len, _len1, _len2, _ref; + either = (function() { + var _i, _len, _ref, _results; + _ref = this.either().children; + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + c = _ref[_i]; + _results.push(c.children); + } + return _results; + }).call(this); + for (_i = 0, _len = either.length; _i < _len; _i++) { + child = either[_i]; + counts = {}; + for (_j = 0, _len1 = child.length; _j < _len1; _j++) { + c = child[_j]; + counts[c] = ((_ref = counts[c]) != null ? _ref : 0) + 1; + } + for (_k = 0, _len2 = child.length; _k < _len2; _k++) { + e = child[_k]; + if (counts[e] > 1 && e.constructor === Option) { + e.value = []; + } + } + } + return this; + }; + Pattern.prototype.either = function() { var c, children, e, either, group, groups, i, indices, name, oneormore, optional, required, ret, types, zip, _i, _j, _len, _len1, _ref, _ref1, _ref2; if (!this.hasOwnProperty('children')) { @@ -221,7 +247,6 @@ })(); Argument = (function(_super) { - __extends(Argument, _super); function Argument(argname, value) { @@ -296,7 +321,6 @@ })(Pattern); Command = (function(_super) { - __extends(Command, _super); function Command(cmdname, value) { @@ -341,7 +365,6 @@ })(Pattern); Option = (function(_super) { - __extends(Option, _super); function Option(short, long, argcount, value) { @@ -384,21 +407,25 @@ }; Option.prototype.match = function(left, collected) { - var l, left_; + var l, left_, values, _i, _len; if (collected == null) { collected = []; } - left_ = (function() { - var _i, _len, _results; - _results = []; - for (_i = 0, _len = left.length; _i < _len; _i++) { - l = left[_i]; - if (l.constructor !== Option || this.short !== l.short || this.long !== l.long) { - _results.push(l); - } + left_ = []; + values = []; + for (_i = 0, _len = left.length; _i < _len; _i++) { + l = left[_i]; + if (l.constructor === Option && this.short === l.short && this.long === l.long) { + values.push(l.value); + } else { + left_.push(l); } - return _results; - }).call(this); + } + if (this.value.constructor === Array) { + console.log(JSON.stringify([this, left])); + this.value = this.value.concat(values); + collected.push(this); + } return [left.join(', ') !== left_.join(', '), left_, collected]; }; @@ -407,7 +434,6 @@ })(Pattern); AnyOptions = (function(_super) { - __extends(AnyOptions, _super); function AnyOptions() { @@ -438,7 +464,6 @@ })(Pattern); Required = (function(_super) { - __extends(Required, _super); function Required() { @@ -468,7 +493,6 @@ })(Pattern); Optional = (function(_super) { - __extends(Optional, _super); function Optional() { @@ -493,7 +517,6 @@ })(Pattern); OneOrMore = (function(_super) { - __extends(OneOrMore, _super); function OneOrMore() { @@ -529,7 +552,6 @@ })(Pattern); Either = (function(_super) { - __extends(Either, _super); function Either() { @@ -570,7 +592,6 @@ })(Pattern); TokenStream = (function(_super) { - __extends(TokenStream, _super); function TokenStream(source, error) { @@ -859,7 +880,6 @@ }; Dict = (function(_super) { - __extends(Dict, _super); function Dict(pairs) { diff --git a/test_docopt.coffee b/test_docopt.coffee index 969eed3..40a717a 100644 --- a/test_docopt.coffee +++ b/test_docopt.coffee @@ -76,7 +76,7 @@ setup() #{new Option, TokenStream, parse_shorts, parse_long, # parse_args, printable_usage, docopt} = module -`with (require('./docopt')) { //` +`with (require('./docopt.coffee')) { //` test "Option.parse", -> eq( @@ -394,6 +394,16 @@ test "parse_pattern", -> ] ] ) + eq( + parse_pattern '(--file )...', o + new Required [ + new OneOrMore [ + new Required [ + new Option '-f', '--file', 1, '' + ] + ] + ] + ) eq( parse_pattern('[ -h | -v ]', o) new Required [ @@ -1027,6 +1037,10 @@ test "options_without_description", -> new Dict([['-v', true], ['--verbose', false]])) eq(docopt('usage: git remote [-v | --verbose]', argv: 'remote -v'), new Dict([['remote', true], ['-v', true], ['--verbose', false]])) + eq(docopt('usage: cmd (--file=)... --l=', argv: '--file=first --file=second --file=third --l=1'), + new Dict([['--file', ['first', 'second', 'third']], ['--l', 1]])) + eq(docopt('usage: cmd (--file=)... --l=...', argv: '--file=first --l=1 --file=second --file=third --l=2'), + new Dict([['--file', ['first', 'second', 'third']], ['--l', [1, 2]]])) test 'allow_single_underscore', ->