diff --git a/spring-shell-docs/src/main/asciidoc/using-shell-options-short.adoc b/spring-shell-docs/src/main/asciidoc/using-shell-options-short.adoc index 79de493e..5b4d2811 100644 --- a/spring-shell-docs/src/main/asciidoc/using-shell-options-short.adoc +++ b/spring-shell-docs/src/main/asciidoc/using-shell-options-short.adoc @@ -2,35 +2,57 @@ === Short Format ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs] -Short style _POSIX_ option in most is just a synonym to long format but -adds additional feature to combine those options together. Having short -options _a_, _b_, _c_ can be used as `-abc`. - -Programmatically short option is defined by using short name function. +Short style _POSIX_ option is usually just a synonym to long format. As +shown below option `--arg` is equal to `-a`. +[tabs] ==== +Programmatic:: ++ [source, java, indent=0] ---- -include::{snippets}/OptionSnippets.java[tag=option-registration-shortarg] +include::{snippets}/ShortOptionSnippets.java[tag=option-type-string-programmatic] +---- + +Annotation:: ++ +[source, java, indent=0] +---- +include::{snippets}/ShortOptionSnippets.java[tag=option-type-string-annotation] +---- + +Legacy Annotation:: ++ +[source, java, indent=0] +---- +include::{snippets}/ShortOptionSnippets.java[tag=option-type-string-legacyannotation] ---- ==== Short option with combined format is powerful if type is defined as a flag -which means type is a _boolean_. That way you can define a presense of a flags +which means type is a _boolean_. That way you can define a presence of a flags as `-abc`, `-abc true` or `-abc false`. +[tabs] ==== +Programmatic:: ++ [source, java, indent=0] ---- -include::{snippets}/OptionSnippets.java[tag=option-registration-shortargbooleans] +include::{snippets}/ShortOptionSnippets.java[tag=option-type-multiple-booleans-programmatic] ---- -==== -With annotation model you can define short argument directly. - -==== +Annotation:: ++ [source, java, indent=0] ---- -include::{snippets}/OptionSnippets.java[tag=option-with-annotation-shortarg] +include::{snippets}/ShortOptionSnippets.java[tag=option-type-multiple-booleans-annotation] +---- + +Legacy Annotation:: ++ +[source, java, indent=0] +---- +include::{snippets}/ShortOptionSnippets.java[tag=option-type-multiple-booleans-legacyannotation] ---- ==== diff --git a/spring-shell-docs/src/test/java/org/springframework/shell/docs/ShortOptionSnippets.java b/spring-shell-docs/src/test/java/org/springframework/shell/docs/ShortOptionSnippets.java new file mode 100644 index 00000000..77a0f305 --- /dev/null +++ b/spring-shell-docs/src/test/java/org/springframework/shell/docs/ShortOptionSnippets.java @@ -0,0 +1,124 @@ +/* + * Copyright 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. + * 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.docs; + +import org.springframework.context.annotation.Bean; +import org.springframework.shell.command.CommandRegistration; +import org.springframework.shell.command.annotation.Command; +import org.springframework.shell.command.annotation.Option; +import org.springframework.shell.standard.ShellMethod; +import org.springframework.shell.standard.ShellOption; + +public class ShortOptionSnippets { + + static class LegacyAnnotation { + + // tag::option-type-string-legacyannotation[] + @ShellMethod(key = "example") + String stringWithShortOption( + @ShellOption(value = { "--arg", "-a" }) String arg) { + return String.format("Hi '%s'", arg); + } + // end::option-type-string-legacyannotation[] + + // tag::option-type-multiple-booleans-legacyannotation[] + @ShellMethod(key = "example") + public String multipleBooleans( + @ShellOption(value = "-a") boolean a, + @ShellOption(value = "-b") boolean b, + @ShellOption(value = "-c") boolean c) + { + return String.format("Hi a='%s' b='%s' c='%s'", a, b, c); + } + // end::option-type-multiple-booleans-legacyannotation[] + } + + // @Command(command = BaseE2ECommands.ANNO, group = BaseE2ECommands.GROUP) + static class Annotation { + + // tag::option-type-string-annotation[] + @Command(command = "example") + String stringWithShortOption( + @Option(longNames = "arg", shortNames = 'a', required = true) String arg) { + return String.format("Hi '%s'", arg); + } + // end::option-type-string-annotation[] + + // tag::option-type-multiple-booleans-annotation[] + @Command(command = "example") + public String multipleBooleans( + @Option(shortNames = 'a') boolean a, + @Option(shortNames = 'b') boolean b, + @Option(shortNames = 'c') boolean c) { + return String.format("Hi a='%s' b='%s' c='%s'", a, b, c); + } + // end::option-type-multiple-booleans-annotation[] + } + + static class Registration { + + // tag::option-type-string-programmatic[] + CommandRegistration stringWithShortOption() { + return CommandRegistration.builder() + .command("example") + .withTarget() + .function(ctx -> { + String arg = ctx.hasMappedOption("arg") ? ctx.getOptionValue("arg") : null; + return String.format("Hi arg='%s'", arg); + }) + .and() + .withOption() + .longNames("arg") + .shortNames('a') + .required() + .and() + .build(); + } + // end::option-type-string-programmatic[] + + // tag::option-type-multiple-booleans-programmatic[] + CommandRegistration multipleBooleans() { + return CommandRegistration.builder() + .command("example") + .withTarget() + .function(ctx -> { + Boolean a = ctx.hasMappedOption("a") ? ctx.getOptionValue("a") : null; + Boolean b = ctx.hasMappedOption("b") ? ctx.getOptionValue("b") : null; + Boolean c = ctx.hasMappedOption("c") ? ctx.getOptionValue("c") : null; + return String.format("Hi a='%s' b='%s' c='%s'", a, b, c); + }) + .and() + .withOption() + .shortNames('a') + .type(boolean.class) + .defaultValue("false") + .and() + .withOption() + .shortNames('b') + .type(boolean.class) + .defaultValue("false") + .and() + .withOption() + .shortNames('c') + .type(boolean.class) + .defaultValue("false") + .and() + .build(); + } + // end::option-type-multiple-booleans-programmatic[] + } + +} diff --git a/spring-shell-samples/src/main/java/org/springframework/shell/samples/e2e/ShortOptionTypeCommands.java b/spring-shell-samples/src/main/java/org/springframework/shell/samples/e2e/ShortOptionTypeCommands.java new file mode 100644 index 00000000..17b86946 --- /dev/null +++ b/spring-shell-samples/src/main/java/org/springframework/shell/samples/e2e/ShortOptionTypeCommands.java @@ -0,0 +1,151 @@ +/* + * Copyright 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. + * 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.command.annotation.Command; +import org.springframework.shell.command.annotation.Option; +import org.springframework.shell.standard.ShellComponent; +import org.springframework.shell.standard.ShellMethod; +import org.springframework.shell.standard.ShellOption; +import org.springframework.stereotype.Component; + +public class ShortOptionTypeCommands { + + @ShellComponent + public static class LegacyAnnotation extends BaseE2ECommands { + + @ShellMethod(key = LEGACY_ANNO + "short-option-type-string", group = GROUP) + public String shortOptionTypeStringLegacyAnnotation( + @ShellOption(value = { "--arg", "-a" }) String arg) { + return String.format("Hi '%s'", arg); + } + + @ShellMethod(key = LEGACY_ANNO + "short-option-type-single-boolean", group = GROUP) + public String shortOptionTypeSingleBooleanLegacyAnnotation( + @ShellOption(value = "-a") boolean a) + { + return String.format("Hi '%s'", a); + } + + @ShellMethod(key = LEGACY_ANNO + "short-option-type-multi-boolean", group = GROUP) + public String shortOptionTypeMultiBooleanLegacyAnnotation( + @ShellOption(value = "-a") boolean a, + @ShellOption(value = "-b") boolean b, + @ShellOption(value = "-c") boolean c) + { + return String.format("Hi a='%s' b='%s' c='%s'", a, b, c); + } + } + + @Command(command = BaseE2ECommands.ANNO, group = BaseE2ECommands.GROUP) + public static class Annotation extends BaseE2ECommands { + + @Command(command = "short-option-type-string") + public String shortOptionTypeStringAnnotation( + @Option(longNames = "arg", shortNames = 'a', required = true) String arg) { + return String.format("Hi '%s'", arg); + } + + @Command(command = "short-option-type-single-boolean") + public String shortOptionTypeSingleBooleanAnnotation( + @Option(shortNames = 'a') boolean a) { + return String.format("Hi '%s'", a); + } + + @Command(command = "short-option-type-multi-boolean") + public String shortOptionTypeMultiBooleanAnnotation( + @Option(shortNames = 'a') boolean a, + @Option(shortNames = 'b') boolean b, + @Option(shortNames = 'c') boolean c) { + return String.format("Hi a='%s' b='%s' c='%s'", a, b, c); + } + } + + @Component + public static class Registration extends BaseE2ECommands { + + @Bean + public CommandRegistration shortOptionTypeStringRegistration() { + return getBuilder() + .command(REG, "short-option-type-string") + .group(GROUP) + .withTarget() + .function(ctx -> { + String arg = ctx.hasMappedOption("arg") ? ctx.getOptionValue("arg") : null; + return String.format("Hi arg='%s'", arg); + }) + .and() + .withOption() + .longNames("arg") + .shortNames('a') + .required() + .and() + .build(); + } + + @Bean + public CommandRegistration shortOptionTypeSingleBooleanRegistration() { + return getBuilder() + .command(REG, "short-option-type-single-boolean") + .group(GROUP) + .withTarget() + .function(ctx -> { + Boolean a = ctx.hasMappedOption("a") ? ctx.getOptionValue("a") : null; + return String.format("Hi a='%s'", a); + }) + .and() + .withOption() + .shortNames('a') + .type(boolean.class) + .defaultValue("false") + .and() + .build(); + } + + @Bean + public CommandRegistration shortOptionTypeMultiBooleanRegistration() { + return getBuilder() + .command(REG, "short-option-type-multi-boolean") + .group(GROUP) + .withTarget() + .function(ctx -> { + Boolean a = ctx.hasMappedOption("a") ? ctx.getOptionValue("a") : null; + Boolean b = ctx.hasMappedOption("b") ? ctx.getOptionValue("b") : null; + Boolean c = ctx.hasMappedOption("c") ? ctx.getOptionValue("c") : null; + return String.format("Hi a='%s' b='%s' c='%s'", a, b, c); + }) + .and() + .withOption() + .shortNames('a') + .type(boolean.class) + .defaultValue("false") + .and() + .withOption() + .shortNames('b') + .type(boolean.class) + .defaultValue("false") + .and() + .withOption() + .shortNames('c') + .type(boolean.class) + .defaultValue("false") + .and() + .build(); + } + } +}