Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -121,65 +121,76 @@ public Object[] apply(List<String> arguments) {

@Override
public String generateHelp() {
final StringBuilder retVal = new StringBuilder();
final StringBuilder argumentLine = new StringBuilder();
final Map<String, String> 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<ArgumentHelp> 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<String, String> 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<String, ParameterParserInfo> 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<String> arguments) {
public boolean isHelp(IArgumentsParser parser, List<String> 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<String> arguments) {
public boolean isHelp(IArgumentsParser parser, List<String> arguments) {
return arguments.isEmpty();
}
};

public abstract boolean isHelp(List<String> arguments);
public abstract boolean isHelp(IArgumentsParser parser, List<String> arguments);
}

protected interface IArgumentsParser extends IFunction1<List<String>, Object[]> {
public String generateHelp();

public boolean isArgumentsRequired();
}

@Data
Expand Down Expand Up @@ -256,8 +267,8 @@ private Constructor<T> findConstructor() {
public T parse(List<String> 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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<RuntimeException> runnable = () -> ArgumentParser.parse(Ordered.class, HCollection.asList());
HAssert.assertThat(runnable, HMatchers.isThrowable(ArgumentHelpException.class, HMatchers.equalTo("\n\nArguments: <string>\n")));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
public class TestArgumentParserHelp {
@Test
public void unparseable() {
assertHelp("<unparseable>", TestArgumentParser.Unparseable.class);
assertHelp("\n\nArguments: <unparseable>\n", TestArgumentParser.Unparseable.class);
}

private void assertHelp(final String help, final Class<?> type) {
Expand All @@ -20,26 +20,26 @@ private void assertHelp(final String help, final Class<?> type) {

@Test
public void array() {
assertHelp("<strings>", TestArgumentParser.Array.class);
assertHelp("\n\nArguments: <strings>\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("<path> [...]\n\npath A path\n--flag An optional flag", TestArgumentParser.Mixed.class);
assertHelp("\n\nArguments: <path> [...]\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("<string>", TestArgumentParser.Ordered.class);
assertHelp("\n\nArguments: <string>\n", TestArgumentParser.Ordered.class);
}
}