Skip to content

Commit

Permalink
Merge pull request #25 from max-au/max-au/otp-25-support
Browse files Browse the repository at this point in the history
[argparse] support OTP 25 'maybe' experimental keyword
  • Loading branch information
max-au authored Mar 13, 2022
2 parents 6a6cc0c + eec1837 commit 4f3762a
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 23 deletions.
4 changes: 2 additions & 2 deletions doc/ARGPARSE.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,10 @@ It is treated the same way as `mycli --arg value`.

For every argument matched, parser may consume several following positional arguments
(not starting with a prefix). Analysis is based on **nargs**, **action** and **type** fields.
* when nargs is **maybe** and next argument is positional, it gets consumed and produced
* when nargs is **'maybe'** and next argument is positional, it gets consumed and produced
as value, and if next argument starts with option prefix, **default** value is produced
(when no default present, default value deduced from argument **type**)
* when nargs is **{maybe, Term}**, and next argument starts with option prefix, Term is
* when nargs is **{'maybe', Term}**, and next argument starts with option prefix, Term is
produced
* when nargs is set to a positive integer, parser tries to consume exactly this
number of positional arguments, and fails with an error if there is not enough.
Expand Down
16 changes: 8 additions & 8 deletions src/argparse.erl
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,8 @@
nargs =>
pos_integer() | %% consume exactly this amount, e.g. '-kernel key value' #{long => "-kernel", args => 2}
%% returns #{kernel => ["key", "value"]}
maybe | %% if next argument is positional, consume it, otherwise produce default
{maybe, term()} | %% if next argument is positional, consume it, otherwise produce term()
'maybe' | %% if next argument is positional, consume it, otherwise produce default
{'maybe', term()} | %% if next argument is positional, consume it, otherwise produce term()
list | %% consume zero or more positional arguments, until next optional
nonempty_list | %% consume at least one positional argument, until next optional
all, %% fold remaining command line into this argument
Expand Down Expand Up @@ -503,9 +503,9 @@ no_digits(true, _, _, Long) ->

%% Returns true when option (!) description passed requires a positional argument,
%% hence cannot be treated as a flag.
requires_argument(#{nargs := {maybe, _Term}}) ->
requires_argument(#{nargs := {'maybe', _Term}}) ->
false;
requires_argument(#{nargs := maybe}) ->
requires_argument(#{nargs := 'maybe'}) ->
false;
requires_argument(#{nargs := _Any}) ->
true;
Expand Down Expand Up @@ -572,7 +572,7 @@ consume(Tail, #{type := boolean} = Opt, Eos) ->
action(Tail, true, Opt#{type => raw}, Eos);

%% maybe behaviour, as '?'
consume(Tail, #{nargs := maybe} = Opt, Eos) ->
consume(Tail, #{nargs := 'maybe'} = Opt, Eos) ->
case split_to_option(Tail, 1, Eos, []) of
{[], _} ->
%% no argument given, produce default argument (if not present,
Expand All @@ -583,7 +583,7 @@ consume(Tail, #{nargs := maybe} = Opt, Eos) ->
end;

%% maybe consume one, maybe not...
consume(Tail, #{nargs := {maybe, Const}} = Opt, Eos) ->
consume(Tail, #{nargs := {'maybe', Const}} = Opt, Eos) ->
case split_to_option(Tail, 1, Eos, []) of
{[], _} ->
action(Tail, Const, Opt, Eos);
Expand Down Expand Up @@ -985,9 +985,9 @@ validate_type(_Type, Path, #{name := Name}) ->
fail({invalid_option, clean_path(Path), Name, type, "unsupported"}).

validate_args(N, _Path, _Opt) when is_integer(N), N >= 1 -> N;
validate_args(Simple, _Path, _Opt) when Simple =:= all; Simple =:= list; Simple =:= maybe; Simple =:= nonempty_list ->
validate_args(Simple, _Path, _Opt) when Simple =:= all; Simple =:= list; Simple =:= 'maybe'; Simple =:= nonempty_list ->
Simple;
validate_args({maybe, Term}, _Path, _Opt) -> {maybe, Term};
validate_args({'maybe', Term}, _Path, _Opt) -> {'maybe', Term};
validate_args(_Nargs, Path, #{name := Name}) ->
fail({invalid_option, clean_path(Path), Name, nargs, "unsupported"}).

Expand Down
26 changes: 13 additions & 13 deletions test/argparse_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,13 @@ ubiq_cmd() ->
#{name => shard, short => $s, type => int, nargs => nonempty_list, help => "initial shards"},
#{name => part, short => $p, type => int, nargs => list, help => hidden},
#{name => z, short => $z, type => {int, [{min, 1}, {max, 10}]}, help => "between"},
#{name => l, short => $l, type => {int, [{max, 10}]}, nargs => maybe, help => "maybe lower"},
#{name => l, short => $l, type => {int, [{max, 10}]}, nargs => 'maybe', help => "maybe lower"},
#{name => more, short => $m, type => {int, [{max, 10}]}, help => "less than 10"},
#{name => optpos, required => false, type => {int, []}, help => "optional positional"},
#{name => bin, short => $b, type => {binary, <<"m">>}, help => "binary with re"},
#{name => g, short => $g, type => {binary, <<"m">>, []}, help => "binary with re"},
#{name => t, short => $t, type => {string, "m"}, help => "string with re"},
#{name => e, long => "--maybe-req", required => true, type => int, nargs => maybe, help => "maybe required int"},
#{name => e, long => "--maybe-req", required => true, type => int, nargs => 'maybe', help => "maybe required int"},
#{name => y, required => true, long => "-yyy", short => $y, type => {string, "m", []}, help => "string with re"},
#{name => u, short => $u, type => {string, ["1", "2"]}, help => "string choices"},
#{name => choice, short => $c, type => {int, [1,2,3]}, help => "tough choice"},
Expand Down Expand Up @@ -442,8 +442,8 @@ args(Config) when is_list(Config) ->
parse_opts(["-x port a b c -x X"], OptsAll)),
%%
OptMaybe = [
#{name => foo, long => "-foo", nargs => {maybe, c}, default => d},
#{name => bar, nargs => maybe, default => d}
#{name => foo, long => "-foo", nargs => {'maybe', c}, default => d},
#{name => bar, nargs => 'maybe', default => d}
],
?assertEqual(#{foo => "YY", bar => "XX"},
parse_opts(["XX --foo YY"], OptMaybe)),
Expand All @@ -453,16 +453,16 @@ args(Config) when is_list(Config) ->
parse_opts([""], OptMaybe)),
%% maybe with default
?assertEqual(#{foo => d, bar => "XX", baz => ok},
parse_opts(["XX -b"], [#{name => baz, nargs => maybe, short => $b, default => ok} | OptMaybe])),
parse_opts(["XX -b"], [#{name => baz, nargs => 'maybe', short => $b, default => ok} | OptMaybe])),
%% maybe arg - with no default given
?assertEqual(#{foo => d, bar => "XX", baz => 0},
parse_opts(["XX -b"], [#{name => baz, nargs => maybe, short => $b, type => int} | OptMaybe])),
parse_opts(["XX -b"], [#{name => baz, nargs => 'maybe', short => $b, type => int} | OptMaybe])),
?assertEqual(#{foo => d, bar => "XX", baz => ""},
parse_opts(["XX -b"], [#{name => baz, nargs => maybe, short => $b, type => string} | OptMaybe])),
parse_opts(["XX -b"], [#{name => baz, nargs => 'maybe', short => $b, type => string} | OptMaybe])),
?assertEqual(#{foo => d, bar => "XX", baz => undefined},
parse_opts(["XX -b"], [#{name => baz, nargs => maybe, short => $b, type => atom} | OptMaybe])),
parse_opts(["XX -b"], [#{name => baz, nargs => 'maybe', short => $b, type => atom} | OptMaybe])),
?assertEqual(#{foo => d, bar => "XX", baz => <<"">>},
parse_opts(["XX -b"], [#{name => baz, nargs => maybe, short => $b, type => binary} | OptMaybe])),
parse_opts(["XX -b"], [#{name => baz, nargs => 'maybe', short => $b, type => binary} | OptMaybe])),
%% nargs: optional list, yet it still needs to be 'not required'!
OptList = [#{name => arg, nargs => list, required => false, type => int}],
?assertEqual(#{}, parse_opts("", OptList)),
Expand Down Expand Up @@ -523,14 +523,14 @@ negative() ->
negative(Config) when is_list(Config) ->
Parser = #{arguments => [
#{name => x, short => $x, type => int, action => store},
#{name => foo, nargs => maybe, required => false}
#{name => foo, nargs => 'maybe', required => false}
]},
?assertEqual(#{x => -1}, parse("-x -1", Parser)),
?assertEqual(#{x => -1, foo => "-5"}, parse("-x -1 -5", Parser)),
%%
Parser2 = #{arguments => [
#{name => one, short => $1},
#{name => foo, nargs => maybe, required => false}
#{name => foo, nargs => 'maybe', required => false}
]},

%% negative number options present, so -1 is an option
Expand Down Expand Up @@ -758,11 +758,11 @@ meta(Config) when is_list(Config) ->
%% extend + maybe
?assertException(error, {argparse, {invalid_option, _, short49, action, _}},
parse("-1 -1", #{arguments =>
[#{action => extend, name => short49, nargs => maybe, short => 49}]})),
[#{action => extend, name => short49, nargs => 'maybe', short => 49}]})),
%%
?assertEqual(#{short49 => 2},
parse("-1 arg1 --force", #{arguments =>
[#{action => count, long => "-force", name => short49, nargs => maybe, short => 49}]})),
[#{action => count, long => "-force", name => short49, nargs => 'maybe', short => 49}]})),
ok.

usage_template() ->
Expand Down

0 comments on commit 4f3762a

Please sign in to comment.