Picocli:使用可选值指定选项的最佳方法,当未指定任何值时,该选项将显示当前值

时间:2018-09-21 12:39:13

标签: command-line-interface command-line-parsing picocli

我正在编写一个REPL(所以我在内部使用picocli来解析在应用程序中键入的命令,而不是解析命令行args),并且我有一个带有选项的命令,我希望这样做: / p>

> cmd --myopt
Myopt value = 5
> cmd --myopt 4
> cmd --myopt
Myopt value = 4

就是说,如果没有指定选项,则打印参数的当前值,但是如果指定有值,则设置该值。我当时想这样做:

int value = 1; // default
@Option(names = {"-e", "--epsilon"}, arity = "0..1",
        description = "Acceptable values: [0, 1] default: ${DEFAULT-VALUE}")
void setValue(String strValue) {
    if (strValue == "") {
        printValue();
    } else {
        try {
            value = Integer.parseInt(strValue);
            // validate value
        } catch (NumberFormatException e) {
            // print help for this option
        }
    }
}

那是最好的方法吗?有没有另一种方法可以捕获描述中的默认值,同时仍然允许setValue知道未指定任何值?

(另请参见https://github.com/remkop/picocli/issues/490

2 个答案:

答案 0 :(得分:1)

我实际上最终采取了不同的方法;这对我的应用程序能够直接分配给实际类型的字段很有帮助(因为我们正在开发一项功能,您可以在其中“发现”带有各种类型参数的命令,因此让该字段为实际类型可以使它反向查找更容易)。

所以我最终这样做了:

static class DoubleConverter implements ITypeConverter<Double> {
    public Double convert(String value) throws Exception {
        if(value.isEmpty()) return Double.NaN; // this is a special value that indicates the option was present without a value
        return Double.valueOf(value);
    }
}

@Option(names = {"-e", "--epsilon"}, arity="0..1", description="Acceptable values: [0, 1] default: 0.1", converter=DoubleConverter.class)
Double epsilon;

基本上,我使用转换器存储特殊值(在本例中为NaN,因为我们最终使用了双精度数),以表明该选项存在而没有任何值(这与根本不存在的值不同,在这种情况下它将为空。

然后按照您建议的在run()方法中执行验证和其他行为:

@Override
public void run() {
    // null indicates the option was not present, so do nothing
    if(epsilon != null) {
        // NaN indicates the option was present but with no value, which means we should print the current value
        if(epsilon.equals(Double.NaN)) {
            // print current value from the application
            printEpsilonValue();
        }
        else {
            // validate value
            if(epsilon < 0.0 || epsilon > 1.0) {
                throw new ParameterException(spec.commandLine(), "Invalid parameter value");
            } else {
                // set the value in the application
                setEpsilonValue(episilon);
            }
        }
    }       
}

我无法使用变量在说明中指定默认值,因为在这种情况下,实际默认值必须为null。不过,这是一个小的牺牲。

我意识到这是一个不寻常的情况,但是支持这种选项(带布尔值0..n的非布尔值)而无需诉诸特殊值可能会很好。也许可以指定另一个字段作为指示该选项是否存在的布尔值。然后,也将不需要自定义转换器,并且可能仍可以指定默认值(即,在这种情况下,Double字段将被设置为默认值,但是如果不存在该选项,则对应的布尔字段将为假,因此应用程序将知道不使用Double的值。

答案 1 :(得分:0)

这当然是做到这一点的一种方法。请记住,setter方法可能会多次调用:一次重置默认值,然后每次在命令行上匹配该选项时再次调用。

另一种方法是将字段类型更改为String,在字段上放置@Option批注,然后从您的{中调用此逻辑(在上面的setValue方法中) {1}}或run方法。