Skip to content

Commit

Permalink
[#320] Rename parser config maxArityIsMaxTotalParams to `arityRestr…
Browse files Browse the repository at this point in the history
…ictsCumulativeSize`

Closes #320
  • Loading branch information
remkop committed Apr 2, 2018
1 parent 82b6054 commit 6abfc56
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 42 deletions.
1 change: 1 addition & 0 deletions RELEASE-NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ No features have been promoted in this picocli release.
## <a name="3.0.0-alpha-4-fixes"></a> Fixed issues

[#318] Split model IBinding into IGetter and ISetter
[#320] Rename parser config `maxArityIsMaxTotalParams` to `arityRestrictsCumulativeSize`


## <a name="3.0.0-alpha-4-deprecated"></a> Deprecations
Expand Down
13 changes: 7 additions & 6 deletions docs/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -655,7 +655,7 @@ ArityDemo -s A B C -f 1.0 2.0 /file1 /file2
Option `-s` has arity `"1..*"` but instead of consuming all parameters,
the `-f` argument is recognized as a separate option.

TIP: It is also possible to <<Max Arity Is Max Total Params,configure the parser>> to use `arity` to limit the total number of values accumulated in an option or positional parameter.
TIP: It is also possible to <<Limiting Cumulative Size,configure the parser>> to use `arity` to limit the total number of values accumulated in an option or positional parameter.

=== Default Arity
If no `arity` is specified, the number of parameters depends on the field's type.
Expand Down Expand Up @@ -792,18 +792,19 @@ Applications can change this by calling `CommandLine.setOverwrittenOptionsAllowe
When overwritten options are allowed, the last specified value takes effect (the above input will set the `port` field to `8080`)
and a WARN level message is printed to the console. (See <<Tracing>> for how to switch off the warnings.)

=== Max Arity Is Max Total Params
=== Limiting Cumulative Size

By default, the <<Arity,arity>> of an option is the number of arguments _for each occurrence_ of the option.
For example, if option `-a` has `arity = "2"`, then the following is a perfectly valid command:
for each occurrence of the option, two option parameters are specified.
----
<command> -a 1 2 -a 3 4 -a 5 6
----
However, if `CommandLine.setMaxArityIsMaxTotalParams(true)` is called first, the above example would result in a `MaxValuesExceededException` because the total number of values (6) exceeds the arity of 2.
However, if `CommandLine.setArityRestrictsCumulativeSize(true)` is called first, `arity` also becomes an upper bound on the number of values accumulated for an option or positional parameter.
The above example would result in a `MaxValuesExceededException` because the total number of values (6) exceeds the arity of 2.

Additionally, by default, when `maxArityIsMaxTotalParams` is `false`, arity is only applied _before_ the argument is <<Split Regex,split>> into parts,
while when `maxArityIsMaxTotalParams` is set to `true`, validation is applied _after_ a command line argument has been split into parts.
Additionally, by default, when `arityRestrictsCumulativeSize` is `false`, arity is only applied _before_ the argument is <<Split Regex,split>> into parts,
while when `arityRestrictsCumulativeSize` is set to `true`, validation is applied _after_ a command line argument has been split into parts.

For example, if we have an option like this:
[source,java]
Expand All @@ -816,7 +817,7 @@ By default, the following input would be a valid command:
----
By default, the option arity tells the parser to consume 1 to 2 arguments, and the option was followed by a single parameter, `"1,2,3"`, which is fine.

However, if `maxArityIsMaxTotalParams` is set to true, the above example would result in a `MaxValuesExceededException` because the argument is split into 3 parts, which exceeds the max arity of 2.
However, if `arityRestrictsCumulativeSize` is set to true, the above example would result in a `MaxValuesExceededException` because the argument is split into 3 parts, which exceeds the max arity of 2.


=== Stop At Positional
Expand Down
28 changes: 14 additions & 14 deletions src/main/java/picocli/CommandLine.java
Original file line number Diff line number Diff line change
Expand Up @@ -352,24 +352,24 @@ public CommandLine setPosixClusteredShortOptionsAllowed(boolean newValue) {
* For example, if option {@code -a} has arity=2, then {@code <command> -a 1 2 -a 3 4 -a 5 6} is a perfectly valid
* command: for each occurrence of the option, two option parameters are specified.
* </p><p>
* However, if {@link ParserSpec#maxArityIsMaxTotalParams() maxArityIsMaxTotalParams} is set to {@code true},
* However, if {@link ParserSpec#arityRestrictsCumulativeSize() arityRestrictsCumulativeSize} is set to {@code true},
* the above example would result in a {@link MaxValuesExceededException} because the total number of values (6) exceeds the arity of 2.
* </p><p>
* Additionally, by default (when {@code maxArityIsMaxTotalParams} is {@code false}), arity is only applied <em>before</em>
* the argument is {@linkplain OptionSpec#splitRegex() split} into parts, while if {@code maxArityIsMaxTotalParams} is set
* Additionally, by default (when {@code arityRestrictsCumulativeSize} is {@code false}), arity is only applied <em>before</em>
* the argument is {@linkplain OptionSpec#splitRegex() split} into parts, while if {@code arityRestrictsCumulativeSize} is set
* to {@code true}, validation is applied <em>after</em> a command line argument has been split into parts.
* </p><p>
* For example, we have an option {@code -a} with {@code arity = "1..2"} and {@code splitRegex = ","}, and the user
* specified {@code <command> -a 1,2,3} on the command line. By default, the option arity tells the parser to consume
* 1 to 2 arguments, and the option was followed by a single argument, {@code "1,2,3"}, which is fine.
* </p><p>
* However, if {@code maxArityIsMaxTotalParams} is set to {@code true}, the above example would result in a
* However, if {@code arityRestrictsCumulativeSize} is set to {@code true}, the above example would result in a
* {@code MaxValuesExceededException} because the argument is split into 3 parts, which exceeds the max arity of 2.
* </p>
* @return {@code true} if a {@link MaxValuesExceededException} should be thrown when the total number of values
* accumulated in an option or positional parameter exceeds the max arity, {@code false} otherwise
* @since 3.0 */
public boolean isMaxArityIsMaxTotalParams() { return getCommandSpec().parser().maxArityIsMaxTotalParams(); }
public boolean isArityRestrictsCumulativeSize() { return getCommandSpec().parser().arityRestrictsCumulativeSize(); }

/** Sets whether the parser should throw an error when the total number of values accumulated in an option or
* positional parameter exceeds the max arity. The default is {@code false}.
Expand All @@ -381,10 +381,10 @@ public CommandLine setPosixClusteredShortOptionsAllowed(boolean newValue) {
* @return this {@code CommandLine} object, to allow method chaining
* @since 3.0
*/
public CommandLine setMaxArityIsMaxTotalParams(boolean newValue) {
getCommandSpec().parser().maxArityIsMaxTotalParams(newValue);
public CommandLine setArityRestrictsCumulativeSize(boolean newValue) {
getCommandSpec().parser().arityRestrictsCumulativeSize(newValue);
for (CommandLine command : getCommandSpec().subcommands().values()) {
command.setMaxArityIsMaxTotalParams(newValue);
command.setArityRestrictsCumulativeSize(newValue);
}
return this;
}
Expand Down Expand Up @@ -3210,7 +3210,7 @@ public static class ParserSpec {
private boolean unmatchedArgumentsAllowed = false;
private boolean expandAtFiles = true;
private boolean posixClusteredShortOptionsAllowed = true;
private boolean maxArityIsMaxTotalParams = false;
private boolean arityRestrictsCumulativeSize = false;

/** Returns the String to use as the separator between options and option parameters. {@code "="} by default,
* initialized from {@link Command#separator()} if defined.*/
Expand All @@ -3222,7 +3222,7 @@ public static class ParserSpec {
public boolean unmatchedArgumentsAllowed() { return unmatchedArgumentsAllowed; }
public boolean expandAtFiles() { return expandAtFiles; }
public boolean posixClusteredShortOptionsAllowed() { return posixClusteredShortOptionsAllowed; }
public boolean maxArityIsMaxTotalParams() { return maxArityIsMaxTotalParams; }
public boolean arityRestrictsCumulativeSize() { return arityRestrictsCumulativeSize; }

/** Sets the String to use as the separator between options and option parameters.
* @return this ParserSpec for method chaining */
Expand All @@ -3233,11 +3233,11 @@ public static class ParserSpec {
public ParserSpec unmatchedArgumentsAllowed(boolean unmatchedArgumentsAllowed) { this.unmatchedArgumentsAllowed = unmatchedArgumentsAllowed; return this; }
public ParserSpec expandAtFiles(boolean expandAtFiles) { this.expandAtFiles = expandAtFiles; return this; }
public ParserSpec posixClusteredShortOptionsAllowed(boolean posixClusteredShortOptionsAllowed) { this.posixClusteredShortOptionsAllowed = posixClusteredShortOptionsAllowed; return this; }
public ParserSpec maxArityIsMaxTotalParams(boolean maxArityIsMaxTotalParams) { this.maxArityIsMaxTotalParams = maxArityIsMaxTotalParams; return this; }
public ParserSpec arityRestrictsCumulativeSize(boolean arityRestrictsCumulativeSize) { this.arityRestrictsCumulativeSize = arityRestrictsCumulativeSize; return this; }
void initSeparator(String value) { if (initializable(separator, value, DEFAULT_SEPARATOR)) {separator = value;} }
public String toString() {
return String.format("posixClusteredShortOptionsAllowed=%s, stopAtPositional=%s, stopAtUnmatched=%s, separator=%s, overwrittenOptionsAllowed=%s, unmatchedArgumentsAllowed=%s, expandAtFiles=%s, maxArityIsMaxTotalParams=%s",
posixClusteredShortOptionsAllowed, stopAtPositional, stopAtUnmatched, separator, overwrittenOptionsAllowed, unmatchedArgumentsAllowed, expandAtFiles, maxArityIsMaxTotalParams);
return String.format("posixClusteredShortOptionsAllowed=%s, stopAtPositional=%s, stopAtUnmatched=%s, separator=%s, overwrittenOptionsAllowed=%s, unmatchedArgumentsAllowed=%s, expandAtFiles=%s, arityRestrictsCumulativeSize=%s",
posixClusteredShortOptionsAllowed, stopAtPositional, stopAtUnmatched, separator, overwrittenOptionsAllowed, unmatchedArgumentsAllowed, expandAtFiles, arityRestrictsCumulativeSize);
}
}
/** Models the shared attributes of {@link OptionSpec} and {@link PositionalParamSpec}.
Expand Down Expand Up @@ -4927,7 +4927,7 @@ private void consumeOneMapArgument(ArgSpec argSpec,
}

private void checkMaxArityExceeded(Range arity, int size, ArgSpec argSpec, String argDescription) {
if (!commandSpec.parser().maxArityIsMaxTotalParams()) { return; }
if (!commandSpec.parser().arityRestrictsCumulativeSize()) { return; }
if (size <= arity.max) { return; }
throw new MaxValuesExceededException(CommandLine.this, optionDescription("", argSpec, -1) +
" max number of values (" + arity.max + ") exceeded: " + size + " elements.");
Expand Down
16 changes: 8 additions & 8 deletions src/test/java/picocli/CommandLineModelTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -949,21 +949,21 @@ public void testCommandSpec_forAnnotatedObjectLenient_returnsEmptyCommandSpec()
}

@Test
public void testParser_MaxArityIsMaxTotalParams_falseByDefault() {
assertFalse(CommandSpec.create().parser().maxArityIsMaxTotalParams());
public void testParser_ArityRestrictsCumulativeSize_falseByDefault() {
assertFalse(CommandSpec.create().parser().arityRestrictsCumulativeSize());
}

@Test
public void testParser_MaxArityIsMaxTotalParams_singleArguments() {
public void testParser_ArityRestrictsCumulativeSize_singleArguments() {
CommandSpec cmd = CommandSpec.create().addOption(OptionSpec.builder("-x").arity("1..3").build());
cmd.parser().maxArityIsMaxTotalParams(true);
cmd.parser().arityRestrictsCumulativeSize(true);

ParseResult parseResult = new CommandLine(cmd).parseArgs("-x 1 -x 2 -x 3".split(" "));
assertEquals(Arrays.asList("1", "2", "3"), parseResult.rawOptionValues('x'));
assertArrayEquals(new String[]{"1", "2", "3"}, parseResult.optionValue('x', (String[]) null));

CommandSpec cmd2 = CommandSpec.create().addOption(OptionSpec.builder("-x").arity("1..3").build());
cmd2.parser().maxArityIsMaxTotalParams(true);
cmd2.parser().arityRestrictsCumulativeSize(true);
try {
new CommandLine(cmd2).parseArgs("-x 1 -x 2 -x 3 -x 4".split(" "));
fail("expected exception");
Expand All @@ -973,17 +973,17 @@ public void testParser_MaxArityIsMaxTotalParams_singleArguments() {
}

@Test
public void testParser_MaxArityIsMaxTotalParams_split() {
public void testParser_ArityRestrictsCumulativeSize_split() {
CommandSpec cmd = CommandSpec.create().addOption(OptionSpec.builder("-x").arity("1..3").splitRegex(",").build());
cmd.parser().maxArityIsMaxTotalParams(true);
cmd.parser().arityRestrictsCumulativeSize(true);

ParseResult parseResult = new CommandLine(cmd).parseArgs("-x", "1,2,3");
assertEquals(Arrays.asList("1", "2", "3"), parseResult.rawOptionValues('x')); // raw is split but untyped
assertEquals(Arrays.asList("1,2,3"), parseResult.option('x').originalStringValues()); // the original command line argument
assertArrayEquals(new String[]{"1", "2", "3"}, parseResult.optionValue('x', (String[]) null));

CommandSpec cmd2 = CommandSpec.create().addOption(OptionSpec.builder("-x").arity("1..3").splitRegex(",").build());
cmd2.parser().maxArityIsMaxTotalParams(true);
cmd2.parser().arityRestrictsCumulativeSize(true);
try {
new CommandLine(cmd2).parseArgs("-x", "1,2,3,4");
fail("expected exception");
Expand Down
28 changes: 14 additions & 14 deletions src/test/java/picocli/CommandLineTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -664,45 +664,45 @@ public void testSetUsageHelpWidth_AfterSubcommandsAdded() {
}

@Test
public void testParserMaxArityIsMaxTotalParams_BeforeSubcommandsAdded() {
public void testParserArityRestrictsCumulativeSize_BeforeSubcommandsAdded() {
@Command class TopLevel {}
CommandLine commandLine = new CommandLine(new TopLevel());
assertEquals(false, commandLine.isMaxArityIsMaxTotalParams());
commandLine.setMaxArityIsMaxTotalParams(true);
assertEquals(true, commandLine.isMaxArityIsMaxTotalParams());
assertEquals(false, commandLine.isArityRestrictsCumulativeSize());
commandLine.setArityRestrictsCumulativeSize(true);
assertEquals(true, commandLine.isArityRestrictsCumulativeSize());

int childCount = 0;
int grandChildCount = 0;
commandLine.addSubcommand("main", createNestedCommand());
for (CommandLine sub : commandLine.getSubcommands().values()) {
childCount++;
assertEquals("subcommand added afterwards is not impacted", false, sub.isMaxArityIsMaxTotalParams());
assertEquals("subcommand added afterwards is not impacted", false, sub.isArityRestrictsCumulativeSize());
for (CommandLine subsub : sub.getSubcommands().values()) {
grandChildCount++;
assertEquals("subcommand added afterwards is not impacted", false, subsub.isMaxArityIsMaxTotalParams());
assertEquals("subcommand added afterwards is not impacted", false, subsub.isArityRestrictsCumulativeSize());
}
}
assertTrue(childCount > 0);
assertTrue(grandChildCount > 0);
}

@Test
public void testParserMaxArityIsMaxTotalParams_AfterSubcommandsAdded() {
public void testParserArityRestrictsCumulativeSize_AfterSubcommandsAdded() {
@Command class TopLevel {}
CommandLine commandLine = new CommandLine(new TopLevel());
commandLine.addSubcommand("main", createNestedCommand());
assertEquals(false, commandLine.isMaxArityIsMaxTotalParams());
commandLine.setMaxArityIsMaxTotalParams(true);
assertEquals(true, commandLine.isMaxArityIsMaxTotalParams());
assertEquals(false, commandLine.isArityRestrictsCumulativeSize());
commandLine.setArityRestrictsCumulativeSize(true);
assertEquals(true, commandLine.isArityRestrictsCumulativeSize());

int childCount = 0;
int grandChildCount = 0;
for (CommandLine sub : commandLine.getSubcommands().values()) {
childCount++;
assertEquals("subcommand added before IS impacted", true, sub.isMaxArityIsMaxTotalParams());
assertEquals("subcommand added before IS impacted", true, sub.isArityRestrictsCumulativeSize());
for (CommandLine subsub : sub.getSubcommands().values()) {
grandChildCount++;
assertEquals("subsubcommand added before IS impacted", true, sub.isMaxArityIsMaxTotalParams());
assertEquals("subsubcommand added before IS impacted", true, sub.isArityRestrictsCumulativeSize());
}
}
assertTrue(childCount > 0);
Expand Down Expand Up @@ -890,7 +890,7 @@ public void testDebugOutputForDoubleDashSeparatesPositionalParameters() throws E
"[picocli DEBUG] Could not register converter for java.nio.file.Path: java.lang.ClassNotFoundException: java.nio.file.Path%n");
String expected = String.format("" +
"[picocli INFO] Parsing 6 command line args [-oout, --, -r, -v, p1, p2]%n" +
"[picocli DEBUG] Parser configuration: posixClusteredShortOptionsAllowed=true, stopAtPositional=false, stopAtUnmatched=false, separator=null, overwrittenOptionsAllowed=false, unmatchedArgumentsAllowed=false, expandAtFiles=true, maxArityIsMaxTotalParams=false%n" +
"[picocli DEBUG] Parser configuration: posixClusteredShortOptionsAllowed=true, stopAtPositional=false, stopAtUnmatched=false, separator=null, overwrittenOptionsAllowed=false, unmatchedArgumentsAllowed=false, expandAtFiles=true, arityRestrictsCumulativeSize=false%n" +
"[picocli DEBUG] Initializing %1$s$CompactFields: 3 options, 1 positional parameters, 0 required, 0 subcommands.%n" +
"[picocli DEBUG] Processing argument '-oout'. Remainder=[--, -r, -v, p1, p2]%n" +
"[picocli DEBUG] '-oout' cannot be separated into <option>=<option-parameter>%n" +
Expand Down Expand Up @@ -1816,7 +1816,7 @@ public void testTracingDebugWithSubCommands() throws Exception {
"[picocli DEBUG] Could not register converter for java.nio.file.Path: java.lang.ClassNotFoundException: java.nio.file.Path%n");
String expected = String.format("" +
"[picocli INFO] Parsing 8 command line args [--git-dir=/home/rpopma/picocli, commit, -m, \"Fixed typos\", --, src1.java, src2.java, src3.java]%n" +
"[picocli DEBUG] Parser configuration: posixClusteredShortOptionsAllowed=true, stopAtPositional=false, stopAtUnmatched=false, separator=null, overwrittenOptionsAllowed=false, unmatchedArgumentsAllowed=false, expandAtFiles=true, maxArityIsMaxTotalParams=false%n" +
"[picocli DEBUG] Parser configuration: posixClusteredShortOptionsAllowed=true, stopAtPositional=false, stopAtUnmatched=false, separator=null, overwrittenOptionsAllowed=false, unmatchedArgumentsAllowed=false, expandAtFiles=true, arityRestrictsCumulativeSize=false%n" +
"[picocli DEBUG] Initializing %1$s$Git: 3 options, 0 positional parameters, 0 required, 12 subcommands.%n" +
"[picocli DEBUG] Processing argument '--git-dir=/home/rpopma/picocli'. Remainder=[commit, -m, \"Fixed typos\", --, src1.java, src2.java, src3.java]%n" +
"[picocli DEBUG] Separated '--git-dir' option from '/home/rpopma/picocli' option parameter%n" +
Expand Down

0 comments on commit 6abfc56

Please sign in to comment.