Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1409 documentation tests #1463

Merged
merged 8 commits into from
Nov 16, 2021
102 changes: 101 additions & 1 deletion docs/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -3033,7 +3033,7 @@ The <<Default Values,default values>> of options in an argument group are applie

Picocli will not initialize the `@ArgGroup`-annotated field (and so no default values are applied) if none of the group options is specified on the command line.

==== Default Values in Group Usage Help
==== Showing Default Values in Group Usage Help

When options are used in argument groups, they can only define default values via the `@Option(defaultValue = "...")` annotation (not in the field declaration).

Expand Down Expand Up @@ -3138,6 +3138,106 @@ usage help shows the wrong default value
----
====

==== Using Default Values in Argument Groups
For picocli, there are two recommendations for successfully employing default values. First, using default values requires setting the default value within the annotation and declaratively within your code. The second is deciding how to instantiate your objects.

[source,role="primary"]
----
@Option(names= {"-x"}, defaultValue = "X") String X = "X";
----
Matching the annotation and declaration ensures that picocli sets the default values regardless of the user supplies the arguments.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it will be good to acknowledge that there is some duplication here, just to be clear and explicit that this is intentional.

Also (nitpicking again), it is actually not picocli who is setting the default value here: remember that the group is not instantiated when there is no match. By setting an initial value, the application is actually doing the work of assigning a default value themselves. I think it is good to be explicit that this is necessary, and mention something like the below, somewhere in this section:

When it comes to assigning default values to options in argument groups, applications need to do extra work that is not necessary with options outside of argument groups.


Next, identify your preferred default behavior. For `+@ArgGroup+`'s there are two distinct ways of instantiating an object.

The first is to instantiate the object declaratively. This behavior is best when you desire no ambiguity in whether or not an `+@ArgGroup+` is instantiated.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This behavior is best when you desire no ambiguity in whether or not an +@ArgGroup+ is instantiated.

I imagine some readers may be confused as to what ambiguity you are referring to. How about something like this?

The first is to instantiate the object in the declaration. This way, the @ArgGroup-annotated field is never null, even if none of the options in that group are specified on the command line.


.Java
[source,java,role="primary"]
----
@ArgGroup MyGroup myGroup = new MyGroup();
----

.Kotlin
[source,kotlin,role="secondary"]
----
@ArgGroup var myGroup = MyGroup();
----

The second way is to initialize the objects using business logic, such as `+run+` or `+call+` methods. This way is better if the desired behavior is to allow the application to determine whether the user specified a value for the `+@ArgGroup+`. It is recommended that the program called using `+execute+` instead of `+parseArgs+`

.Java
[source,java,role="primary"]
----
@Command(name = "test", description = "demonstrates Default Value declaration")
class MyApp {
@ArgGroup Outer outer;

static class Outer {
@Options(names = "-x", defaultValue = "XX") String x = "XX";
@ArgGroup(exclusive = "true") Inner inner;
}

static class Inner {
@Options(names = "-a", defaultValue = "AA") String a = "AA";
@Options(names = "-b", defaultValue = "BB") String b = "BB";
}

public void run() {
if (outer == null) { // no options specified on command line; apply default values
outer = new Outer;
}
if (outer.inner == null) { // handle nested sub-groups; apply default for inner group
outer.inner = new Inner;
}

// remaining business logic...
}
remkop marked this conversation as resolved.
Show resolved Hide resolved
}

public static void main() {
final MyApp obj = new MyApp();
new CommandLine(obj).execute("-x", "ANOTHER_VALUE");
}
----

.Kotlin
[source,kotlin,role="secondary"]
----

import sun.tools.jar.CommandLine@Command(name = "test", description =["demonstrates Default Value declaration"])
class MyApp {
@ArgGroup lateinit var outer: Outer

class Outer {
@Options(names = "-x", defaultValue = "XX") var x = "XX";
@ArgGroup lateinit var inner: Inner
}

class Inner {
@Options(names = "-a", defaultValue = "AA") var a : "AA"
@Options(names = "-b", defaultValue = "BB") var b : "BB"
}

override fun run() {
if (outer == null) { // no options specified on command line; apply default values
outer = Outer();
}
if (outer.inner == null) { // handle nested sub-groups; apply default for inner group
outer.inner = Inner();
}

// remaining business logic...
}
}

remkop marked this conversation as resolved.
Show resolved Hide resolved
fun main(args: Array<String>) {
var obj = MyApp();
var commandLine = CommandLine(obj);
commandLine.execute(args);
}
----


=== Positional Parameters

When a `@Parameters` positional parameter is part of a group, its `index` is the index _within the group_, not within the command.
Expand Down
Loading