Support modify option names
- New OptionNameModifier which is just a Function<String,String> to modify a name. - Can be defined per option in CommandRegistration. - Can be defined as global default as bean. - Default implementation for common case types is enabled via boot's config props under spring.shell.option.naming.case-type - Support facilities for camel, kebab, snake and pascal conversions. - Fixes #621
This commit is contained in:
@@ -20,7 +20,9 @@ import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.shell.MethodTargetRegistrar;
|
||||
@@ -29,6 +31,8 @@ import org.springframework.shell.command.CommandCatalog;
|
||||
import org.springframework.shell.command.CommandCatalogCustomizer;
|
||||
import org.springframework.shell.command.CommandRegistration;
|
||||
import org.springframework.shell.command.CommandRegistration.BuilderSupplier;
|
||||
import org.springframework.shell.command.CommandRegistration.OptionNameModifier;
|
||||
import org.springframework.shell.command.support.OptionNameModifierSupport;
|
||||
import org.springframework.shell.command.CommandResolver;
|
||||
|
||||
@AutoConfiguration
|
||||
@@ -74,6 +78,40 @@ public class CommandCatalogAutoConfiguration {
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnBean(OptionNameModifier.class)
|
||||
public CommandRegistrationCustomizer customOptionNameModifierCommandRegistrationCustomizer(OptionNameModifier modifier) {
|
||||
return builder -> {
|
||||
builder.defaultOptionNameModifier(modifier);
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(OptionNameModifier.class)
|
||||
@ConditionalOnProperty(prefix = "spring.shell.option.naming", name = "case-type")
|
||||
public CommandRegistrationCustomizer defaultOptionNameModifierCommandRegistrationCustomizer(SpringShellProperties properties) {
|
||||
return builder -> {
|
||||
switch (properties.getOption().getNaming().getCaseType()) {
|
||||
case NOOP:
|
||||
break;
|
||||
case CAMEL:
|
||||
builder.defaultOptionNameModifier(OptionNameModifierSupport.CAMELCASE);
|
||||
break;
|
||||
case SNAKE:
|
||||
builder.defaultOptionNameModifier(OptionNameModifierSupport.SNAKECASE);
|
||||
break;
|
||||
case KEBAB:
|
||||
builder.defaultOptionNameModifier(OptionNameModifierSupport.KEBABCASE);
|
||||
break;
|
||||
case PASCAL:
|
||||
builder.defaultOptionNameModifier(OptionNameModifierSupport.PASCALCASE);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public BuilderSupplier commandRegistrationBuilderSupplier(
|
||||
|
||||
@@ -33,6 +33,7 @@ public class SpringShellProperties {
|
||||
private Theme theme = new Theme();
|
||||
private Command command = new Command();
|
||||
private Help help = new Help();
|
||||
private Option option = new Option();
|
||||
|
||||
public void setConfig(Config config) {
|
||||
this.config = config;
|
||||
@@ -98,6 +99,14 @@ public class SpringShellProperties {
|
||||
return help;
|
||||
}
|
||||
|
||||
public Option getOption() {
|
||||
return option;
|
||||
}
|
||||
|
||||
public void setOption(Option option) {
|
||||
this.option = option;
|
||||
}
|
||||
|
||||
public static class Config {
|
||||
|
||||
private String env;
|
||||
@@ -559,4 +568,38 @@ public class SpringShellProperties {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Option {
|
||||
|
||||
private OptionNaming naming = new OptionNaming();
|
||||
|
||||
public OptionNaming getNaming() {
|
||||
return naming;
|
||||
}
|
||||
|
||||
public void setNaming(OptionNaming naming) {
|
||||
this.naming = naming;
|
||||
}
|
||||
}
|
||||
|
||||
public static class OptionNaming {
|
||||
private OptionNamingCase caseType = OptionNamingCase.NOOP;
|
||||
|
||||
public OptionNamingCase getCaseType() {
|
||||
return caseType;
|
||||
}
|
||||
|
||||
public void setCaseType(OptionNamingCase caseType) {
|
||||
this.caseType = caseType;
|
||||
}
|
||||
}
|
||||
|
||||
public static enum OptionNamingCase {
|
||||
NOOP,
|
||||
CAMEL,
|
||||
SNAKE,
|
||||
KEBAB,
|
||||
PASCAL
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2022 the original author or authors.
|
||||
* Copyright 2022-2023 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.
|
||||
@@ -27,6 +27,9 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.shell.command.CommandCatalog;
|
||||
import org.springframework.shell.command.CommandRegistration;
|
||||
import org.springframework.shell.command.CommandResolver;
|
||||
import org.springframework.shell.command.CommandRegistration.Builder;
|
||||
import org.springframework.shell.command.CommandRegistration.BuilderSupplier;
|
||||
import org.springframework.shell.command.CommandRegistration.OptionNameModifier;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -68,6 +71,82 @@ public class CommandCatalogAutoConfigurationTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void builderSupplierIsCreated() {
|
||||
this.contextRunner
|
||||
.run(context -> {
|
||||
BuilderSupplier builderSupplier = context.getBean(BuilderSupplier.class);
|
||||
assertThat(builderSupplier).isNotNull();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultOptionNameModifierIsNull() {
|
||||
this.contextRunner
|
||||
.run(context -> {
|
||||
BuilderSupplier builderSupplier = context.getBean(BuilderSupplier.class);
|
||||
Builder builder = builderSupplier.get();
|
||||
assertThat(builder).extracting("defaultOptionNameModifier").isNull();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultOptionNameModifierIsSet() {
|
||||
this.contextRunner
|
||||
.withUserConfiguration(CustomOptionNameModifierConfiguration.class)
|
||||
.run(context -> {
|
||||
BuilderSupplier builderSupplier = context.getBean(BuilderSupplier.class);
|
||||
Builder builder = builderSupplier.get();
|
||||
assertThat(builder).extracting("defaultOptionNameModifier").isNotNull();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultOptionNameModifierIsSetFromProperties() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.shell.option.naming.case-type=kebab")
|
||||
.run(context -> {
|
||||
BuilderSupplier builderSupplier = context.getBean(BuilderSupplier.class);
|
||||
Builder builder = builderSupplier.get();
|
||||
assertThat(builder).extracting("defaultOptionNameModifier").isNotNull();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultOptionNameModifierNoopNotSetFromProperties() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.shell.option.naming.case-type=noop")
|
||||
.run(context -> {
|
||||
BuilderSupplier builderSupplier = context.getBean(BuilderSupplier.class);
|
||||
Builder builder = builderSupplier.get();
|
||||
assertThat(builder).extracting("defaultOptionNameModifier").isNull();
|
||||
// there is customizer but it doesn't do anything
|
||||
assertThat(context).hasBean("defaultOptionNameModifierCommandRegistrationCustomizer");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void noCustomizerIfPropertyIsNotSet() {
|
||||
this.contextRunner
|
||||
.run(context -> {
|
||||
BuilderSupplier builderSupplier = context.getBean(BuilderSupplier.class);
|
||||
Builder builder = builderSupplier.get();
|
||||
assertThat(builder).extracting("defaultOptionNameModifier").isNull();
|
||||
// no customizer added without property
|
||||
assertThat(context).doesNotHaveBean("defaultOptionNameModifierCommandRegistrationCustomizer");
|
||||
});
|
||||
}
|
||||
|
||||
// defaultOptionNameModifierCommandRegistrationCustomizer
|
||||
@Configuration
|
||||
static class CustomOptionNameModifierConfiguration {
|
||||
|
||||
@Bean
|
||||
OptionNameModifier customOptionNameModifier() {
|
||||
return name -> name;
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class CustomCommandResolverConfiguration {
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.shell.boot.SpringShellProperties.OptionNamingCase;
|
||||
import org.springframework.shell.boot.SpringShellProperties.HelpCommand.GroupingMode;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -67,6 +68,7 @@ public class SpringShellPropertiesTests {
|
||||
assertThat(properties.getHelp().getCommand()).isEqualTo("help");
|
||||
assertThat(properties.getHelp().getLongNames()).containsExactly("help");
|
||||
assertThat(properties.getHelp().getShortNames()).containsExactly('h');
|
||||
assertThat(properties.getOption().getNaming().getCaseType()).isEqualTo(OptionNamingCase.NOOP);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -107,6 +109,7 @@ public class SpringShellPropertiesTests {
|
||||
.withPropertyValues("spring.shell.help.command=fake")
|
||||
.withPropertyValues("spring.shell.help.long-names=fake")
|
||||
.withPropertyValues("spring.shell.help.short-names=f")
|
||||
.withPropertyValues("spring.shell.option.naming.case-type=camel")
|
||||
.withUserConfiguration(Config1.class)
|
||||
.run((context) -> {
|
||||
SpringShellProperties properties = context.getBean(SpringShellProperties.class);
|
||||
@@ -144,6 +147,7 @@ public class SpringShellPropertiesTests {
|
||||
assertThat(properties.getHelp().getCommand()).isEqualTo("fake");
|
||||
assertThat(properties.getHelp().getLongNames()).containsExactly("fake");
|
||||
assertThat(properties.getHelp().getShortNames()).containsExactly('f');
|
||||
assertThat(properties.getOption().getNaming().getCaseType()).isEqualTo(OptionNamingCase.CAMEL);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user