Support option label

- This adds `label` to `CommandOption` which is then used
  in a Help instead of type.
- Fixes #424
This commit is contained in:
Janne Valkealahti
2022-06-08 07:39:44 +01:00
parent 8548828873
commit fa65a2308e
6 changed files with 113 additions and 9 deletions

View File

@@ -87,6 +87,13 @@ public interface CommandOption {
*/
int getArityMax();
/**
* Gets a label.
*
* @return the label
*/
String getLabel();
/**
* Gets an instance of a default {@link CommandOption}.
*
@@ -96,7 +103,7 @@ public interface CommandOption {
* @return default command option
*/
public static CommandOption of(String[] longNames, Character[] shortNames, String description) {
return of(longNames, shortNames, description, null, false, null, null, null, null);
return of(longNames, shortNames, description, null, false, null, null, null, null, null);
}
/**
@@ -110,7 +117,7 @@ public interface CommandOption {
*/
public static CommandOption of(String[] longNames, Character[] shortNames, String description,
ResolvableType type) {
return of(longNames, shortNames, description, type, false, null, null, null, null);
return of(longNames, shortNames, description, type, false, null, null, null, null, null);
}
/**
@@ -125,12 +132,14 @@ public interface CommandOption {
* @param position the position value
* @param arityMin the min arity
* @param arityMax the max arity
* @param label the label
* @return default command option
*/
public static CommandOption of(String[] longNames, Character[] shortNames, String description,
ResolvableType type, boolean required, String defaultValue, Integer position, Integer arityMin, Integer arityMax) {
ResolvableType type, boolean required, String defaultValue, Integer position, Integer arityMin,
Integer arityMax, String label) {
return new DefaultCommandOption(longNames, shortNames, description, type, required, defaultValue, position,
arityMin, arityMax);
arityMin, arityMax, label);
}
/**
@@ -147,10 +156,11 @@ public interface CommandOption {
private int position;
private int arityMin;
private int arityMax;
private String label;
public DefaultCommandOption(String[] longNames, Character[] shortNames, String description,
ResolvableType type, boolean required, String defaultValue, Integer position,
Integer arityMin, Integer arityMax) {
Integer arityMin, Integer arityMax, String label) {
this.longNames = longNames != null ? longNames : new String[0];
this.shortNames = shortNames != null ? shortNames : new Character[0];
this.description = description;
@@ -160,6 +170,7 @@ public interface CommandOption {
this.position = position != null && position > -1 ? position : -1 ;
this.arityMin = arityMin != null ? arityMin : -1;
this.arityMax = arityMax != null ? arityMax : -1;
this.label = label;
}
@Override
@@ -206,5 +217,10 @@ public interface CommandOption {
public int getArityMax() {
return arityMax;
}
@Override
public String getLabel() {
return label;
}
}
}

View File

@@ -200,6 +200,14 @@ public interface CommandRegistration {
*/
OptionSpec arity(OptionArity arity);
/**
* Define a {@code label} for an option.
*
* @param label the label
* @return option spec for chaining
*/
OptionSpec label(String label);
/**
* Return a builder for chaining.
*
@@ -519,6 +527,7 @@ public interface CommandRegistration {
private Integer position;
private Integer arityMin;
private Integer arityMax;
private String label;
DefaultOptionSpec(BaseBuilder builder) {
this.builder = builder;
@@ -611,6 +620,12 @@ public interface CommandRegistration {
return this;
}
@Override
public OptionSpec label(String label) {
this.label = label;
return this;
}
@Override
public Builder and() {
return builder;
@@ -651,6 +666,10 @@ public interface CommandRegistration {
public Integer getArityMax() {
return arityMax;
}
public String getLabel() {
return label;
}
}
static class DefaultTargetSpec implements TargetSpec {
@@ -820,7 +839,8 @@ public interface CommandRegistration {
public List<CommandOption> getOptions() {
return optionSpecs.stream()
.map(o -> CommandOption.of(o.getLongNames(), o.getShortNames(), o.getDescription(), o.getType(),
o.isRequired(), o.getDefaultValue(), o.getPosition(), o.getArityMin(), o.getArityMax()))
o.isRequired(), o.getDefaultValue(), o.getPosition(), o.getArityMin(), o.getArityMax(),
o.getLabel()))
.collect(Collectors.toList());
}

View File

@@ -327,7 +327,7 @@ public class CommandParserTests extends AbstractCommandTests {
public void testBooleanWithDefault() {
ResolvableType type = ResolvableType.forType(boolean.class);
CommandOption option1 = CommandOption.of(new String[] { "arg1" }, new Character[0], "description", type, false,
"true", null, null, null);
"true", null, null, null, null);
List<CommandOption> options = Arrays.asList(option1);
String[] args = new String[]{};
@@ -359,7 +359,7 @@ public class CommandParserTests extends AbstractCommandTests {
private static CommandOption longOption(String name, ResolvableType type, boolean required, Integer position, Integer arityMin, Integer arityMax) {
return CommandOption.of(new String[] { name }, new Character[0], "desc", type, required, null, position,
arityMin, arityMax);
arityMin, arityMax, null);
}
private static CommandOption shortOption(char name) {

View File

@@ -195,6 +195,7 @@ public class CommandRegistrationTests extends AbstractCommandTests {
.shortNames('v')
.type(boolean.class)
.description("some arg1")
.label("mylabel")
.and()
.withTarget()
.function(function1)
@@ -205,6 +206,7 @@ public class CommandRegistrationTests extends AbstractCommandTests {
assertThat(registration.getOptions()).hasSize(1);
assertThat(registration.getOptions().get(0).getShortNames()).containsExactly('v');
assertThat(registration.getOptions().get(0).getType()).isEqualTo(ResolvableType.forType(boolean.class));
assertThat(registration.getOptions().get(0).getLabel()).isEqualTo("mylabel");
}
@Test

View File

@@ -0,0 +1,56 @@
/*
* Copyright 2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.shell.samples.e2e;
import org.springframework.context.annotation.Bean;
import org.springframework.shell.command.CommandRegistration;
import org.springframework.shell.standard.ShellComponent;
/**
* Commands used for e2e test.
*
* @author Janne Valkealahti
*/
@ShellComponent
public class OptionTypeCommands extends BaseE2ECommands {
@Bean
public CommandRegistration testOptionTypeRegistration() {
return CommandRegistration.builder()
.command(REG, "option-type")
.group(GROUP)
.withOption()
.longNames("arg1")
.and()
.withOption()
.longNames("arg2")
.type(String.class)
.and()
.withOption()
.longNames("arg3")
.type(int.class)
.and()
.withOption()
.longNames("arg4")
.label("MYLABEL")
.and()
.withTarget()
.consumer(ctx -> {})
.and()
.build();
}
}

View File

@@ -22,6 +22,7 @@ import java.util.stream.Stream;
import org.springframework.shell.command.CommandOption;
import org.springframework.shell.command.CommandRegistration;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
/**
* Model encapsulating info about {@code command}.
@@ -51,7 +52,7 @@ class CommandInfoModel {
List<CommandOption> options = registration.getOptions();
List<CommandParameterInfoModel> parameters = options.stream()
.map(o -> {
String type = o.getType() == null ? "String" : ClassUtils.getShortName(o.getType().getRawClass());
String type = commandOptionType(o);
List<String> arguments = Stream.concat(
Stream.of(o.getLongNames()).map(a -> "--" + a),
Stream.of(o.getShortNames()).map(s -> "-" + s))
@@ -67,6 +68,15 @@ class CommandInfoModel {
return new CommandInfoModel(name, description, parameters);
}
private static String commandOptionType(CommandOption o) {
if (StringUtils.hasText(o.getLabel())) {
return o.getLabel();
}
else {
return o.getType() == null ? "String" : ClassUtils.getShortName(o.getType().getRawClass());
}
}
public String getName() {
return name;
}