diff --git a/gb-argparse/src/main/java/com/g2forge/gearbox/argparse/ArgumentParser.java b/gb-argparse/src/main/java/com/g2forge/gearbox/argparse/ArgumentParser.java index 45d7b4a..dc593f9 100644 --- a/gb-argparse/src/main/java/com/g2forge/gearbox/argparse/ArgumentParser.java +++ b/gb-argparse/src/main/java/com/g2forge/gearbox/argparse/ArgumentParser.java @@ -121,65 +121,76 @@ public Object[] apply(List arguments) { @Override public String generateHelp() { - final StringBuilder retVal = new StringBuilder(); + final StringBuilder argumentLine = new StringBuilder(); final Map positionalHelp = new LinkedHashMap<>(); for (ParameterParserInfo info : positional) { final IParameterInfo parameter = parameters.get(info.getIndex()); - if (!retVal.isEmpty()) retVal.append(' '); - retVal.append('<').append(parameter.getName()).append('>'); + if (!argumentLine.isEmpty()) argumentLine.append(' '); + argumentLine.append('<').append(parameter.getName()).append('>'); final IPredicate predicate = parameter.getSubject().bind(ArgumentHelp.class); if (predicate.isPresent()) positionalHelp.put(parameter.getName(), predicate.get0().value()); } - final boolean hasNamed = named.isEmpty(); - if (!hasNamed && !retVal.isEmpty()) retVal.append(" [...]"); - if (!positionalHelp.isEmpty() || !hasNamed) { - if (!retVal.isEmpty()) retVal.append("\n"); + final boolean hasNamed = !named.isEmpty(); + if (hasNamed && !argumentLine.isEmpty()) argumentLine.append(" [...]"); + + final StringBuilder retVal = new StringBuilder(); + retVal.append(argumentLine.isEmpty() ? "No Positional Arguments" : "Arguments: "); + retVal.append(argumentLine); + if (!positionalHelp.isEmpty() || hasNamed) { final int padded = HStream.concat(positionalHelp.keySet().stream(), named.keySet().stream()).mapToInt(String::length).max().getAsInt(); if (!positionalHelp.isEmpty()) { for (Map.Entry entry : positionalHelp.entrySet()) { if (!retVal.isEmpty()) retVal.append('\n'); - retVal.append(entry.getKey()).append(' ').append(entry.getValue()); + retVal.append('\t').append(HString.pad(entry.getKey(), " ", padded)).append(" - ").append(entry.getValue()); } } - if (!hasNamed) { + if (hasNamed) { for (Map.Entry entry : named.entrySet()) { if (!retVal.isEmpty()) retVal.append('\n'); final IParameterInfo parameter = parameters.get(entry.getValue().getIndex()); - retVal.append(HString.pad(entry.getKey(), " ", padded)); + retVal.append('\t').append(HString.pad(entry.getKey(), " ", padded)); final ArgumentHelp argumentHelp = parameter.getSubject().get(ArgumentHelp.class); - if (argumentHelp != null) retVal.append(' ').append(argumentHelp.value()); + if (argumentHelp != null) retVal.append(" - ").append(argumentHelp.value()); } } } return retVal.toString(); } + + @Override + public boolean isArgumentsRequired() { + return !positional.isEmpty(); + } } public enum HelpArguments { STANDARD { @Override - public boolean isHelp(List arguments) { + public boolean isHelp(IArgumentsParser parser, List arguments) { + if (parser.isArgumentsRequired() && arguments.isEmpty()) return true; if (arguments.size() == 1) return STANDARD_HELP_ARGUMENTS.contains(arguments.get(0)); return false; } }, EMPTY { @Override - public boolean isHelp(List arguments) { + public boolean isHelp(IArgumentsParser parser, List arguments) { return arguments.isEmpty(); } }; - public abstract boolean isHelp(List arguments); + public abstract boolean isHelp(IArgumentsParser parser, List arguments); } protected interface IArgumentsParser extends IFunction1, Object[]> { public String generateHelp(); + + public boolean isArgumentsRequired(); } @Data @@ -256,8 +267,8 @@ private Constructor findConstructor() { public T parse(List arguments) { final IArgumentsParser argumentsParser = getArgumentsParser(); - final boolean help = getHelp().stream().filter(helpArguments -> helpArguments.isHelp(arguments)).findAny().isPresent(); - if (help) throw new ArgumentHelpException(argumentsParser.generateHelp()); + final boolean help = getHelp().stream().filter(helpArguments -> helpArguments.isHelp(argumentsParser, arguments)).findAny().isPresent(); + if (help) throw new ArgumentHelpException("\n\n" + argumentsParser.generateHelp() + "\n"); final Object[] parsed = argumentsParser.apply(arguments); return create(parsed); diff --git a/gb-argparse/src/test/java/com/g2forge/gearbox/argparse/TestArgumentParser.java b/gb-argparse/src/test/java/com/g2forge/gearbox/argparse/TestArgumentParser.java index 0ef913b..ccb73cc 100644 --- a/gb-argparse/src/test/java/com/g2forge/gearbox/argparse/TestArgumentParser.java +++ b/gb-argparse/src/test/java/com/g2forge/gearbox/argparse/TestArgumentParser.java @@ -6,7 +6,9 @@ import org.junit.Test; import com.g2forge.alexandria.java.core.helpers.HCollection; +import com.g2forge.alexandria.java.function.IThrowRunnable; import com.g2forge.alexandria.test.HAssert; +import com.g2forge.alexandria.test.HMatchers; import lombok.AllArgsConstructor; import lombok.Builder; @@ -95,7 +97,8 @@ public void flagTrue() { @Test public void missing() { - HAssert.assertException(UnspecifiedParameterException.class, "Parameter #0 (string) was not specified!", () -> ArgumentParser.parse(Ordered.class, HCollection.asList())); + final IThrowRunnable runnable = () -> ArgumentParser.parse(Ordered.class, HCollection.asList()); + HAssert.assertThat(runnable, HMatchers.isThrowable(ArgumentHelpException.class, HMatchers.equalTo("\n\nArguments: \n"))); } @Test diff --git a/gb-argparse/src/test/java/com/g2forge/gearbox/argparse/TestArgumentParserHelp.java b/gb-argparse/src/test/java/com/g2forge/gearbox/argparse/TestArgumentParserHelp.java index 554a2d1..4bd3914 100644 --- a/gb-argparse/src/test/java/com/g2forge/gearbox/argparse/TestArgumentParserHelp.java +++ b/gb-argparse/src/test/java/com/g2forge/gearbox/argparse/TestArgumentParserHelp.java @@ -10,7 +10,7 @@ public class TestArgumentParserHelp { @Test public void unparseable() { - assertHelp("", TestArgumentParser.Unparseable.class); + assertHelp("\n\nArguments: \n", TestArgumentParser.Unparseable.class); } private void assertHelp(final String help, final Class type) { @@ -20,26 +20,26 @@ private void assertHelp(final String help, final Class type) { @Test public void array() { - assertHelp("", TestArgumentParser.Array.class); + assertHelp("\n\nArguments: \n", TestArgumentParser.Array.class); } @Test public void flag() { - assertHelp("--flag", TestArgumentParser.Flag.class); + assertHelp("\n\nNo Positional Arguments\n\t--flag\n", TestArgumentParser.Flag.class); } @Test public void mixed() { - assertHelp(" [...]\n\npath A path\n--flag An optional flag", TestArgumentParser.Mixed.class); + assertHelp("\n\nArguments: [...]\n\tpath - A path\n\t--flag - An optional flag\n", TestArgumentParser.Mixed.class); } @Test public void none() { - assertHelp("", TestArgumentParser.None.class); + assertHelp("\n\nNo Positional Arguments\n", TestArgumentParser.None.class); } @Test public void ordered() { - assertHelp("", TestArgumentParser.Ordered.class); + assertHelp("\n\nArguments: \n", TestArgumentParser.Ordered.class); } }