diff --git a/README.md b/README.md
index 1d470a1a..1a83a354 100644
--- a/README.md
+++ b/README.md
@@ -82,7 +82,7 @@ The package is currently only available on GitHub Packages.
implementation("darvil:lanat")
```
- Note that you may need to explicitly specify the version of the package you want to use. (e.g. `darvil:lanat:0.0.1`)
+ Note that you may need to explicitly specify the version of the package you want to use. (e.g. `darvil:lanat:x.x.x`)
This information is available at the [GitHub Packages documentation](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-gradle-registry#using-a-published-package).
diff --git a/build.gradle.kts b/build.gradle.kts
index b631a142..15dcd597 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -4,7 +4,7 @@ plugins {
}
group = "darvil"
-version = "0.0.2"
+version = "0.0.3"
description = "Command line argument parser"
dependencies {
diff --git a/src/main/java/lanat/Argument.java b/src/main/java/lanat/Argument.java
index ded72661..a5cf726b 100644
--- a/src/main/java/lanat/Argument.java
+++ b/src/main/java/lanat/Argument.java
@@ -476,7 +476,7 @@ public void parseValues(short tokenIndex, @NotNull String... values) {
*/
public @Nullable TInner finishParsing() {
final TInner finalValue = this.argType.getFinalValue();
- final TInner defaultValue = this.defaultValue == null ? this.argType.getInitialValue() : this.defaultValue;
+ final TInner defaultValue = UtlMisc.nonNullOrElse(this.defaultValue, this.argType.getInitialValue());
/* no, | is not a typo. We don't want the OR operator to short-circuit, we want all of them to be evaluated
* because the methods have side effects (they add errors to the parser) */
@@ -597,6 +597,7 @@ void invokeCallbacks(@Nullable Object okValue) {
*/
@Override
public boolean equals(@NotNull Object obj) {
+ if (obj == this) return true;
if (obj instanceof Argument, ?> arg)
return UtlMisc.equalsByNamesAndParentCmd(this, arg);
return false;
diff --git a/src/main/java/lanat/ArgumentAdder.java b/src/main/java/lanat/ArgumentAdder.java
index dcfc52bd..2f799e54 100644
--- a/src/main/java/lanat/ArgumentAdder.java
+++ b/src/main/java/lanat/ArgumentAdder.java
@@ -39,7 +39,7 @@ void addArgument(@NotNull ArgumentBuilder argument) {
@NotNull List<@NotNull Argument, ?>> getArguments();
/**
- * Checks that all the arguments in this container have unique names.
+ * Checks that all the arguments in this container are unique.
* @throws ArgumentAlreadyExistsException if there are two arguments with the same name
*/
default void checkUniqueArguments() {
diff --git a/src/main/java/lanat/ArgumentBuilder.java b/src/main/java/lanat/ArgumentBuilder.java
index 09ee1f15..5c20e4ea 100644
--- a/src/main/java/lanat/ArgumentBuilder.java
+++ b/src/main/java/lanat/ArgumentBuilder.java
@@ -1,6 +1,7 @@
package lanat;
import lanat.argumentTypes.DummyArgumentType;
+import lanat.exceptions.ArgumentTypeInferException;
import lanat.utils.UtlReflection;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -47,16 +48,17 @@ public class ArgumentBuilder, TInner> {
if (annotation.argType() != DummyArgumentType.class)
return UtlReflection.instantiate(annotation.argType());
- // try to infer the type from the field type
- var argTypeMap = ArgumentType.getTypeInfer(field.getType());
-
- // if the type was not found, return null
- return argTypeMap == null ? null : UtlReflection.instantiate(argTypeMap);
+ // try to infer the type from the field type. If it can't be inferred, return null
+ try {
+ return ArgumentTypeInfer.get(field.getType());
+ } catch (ArgumentTypeInferException e) {
+ return null;
+ }
}
/**
* Builds an {@link Argument} from the specified field annotated with {@link Argument.Define}.
- * Note that this doesn't set the argument type.
+ * Note that this doesn't set the argument type. Use {@link #setArgTypeFromField(Field)} for that.
*
* @param field the field that will be used to build the argument
* @param the {@link ArgumentType} subclass that will parse the value passed to the argument
diff --git a/src/main/java/lanat/ArgumentGroup.java b/src/main/java/lanat/ArgumentGroup.java
index fcc230a8..9053157e 100644
--- a/src/main/java/lanat/ArgumentGroup.java
+++ b/src/main/java/lanat/ArgumentGroup.java
@@ -75,8 +75,8 @@ public class ArgumentGroup
* each one added to this group is because at parsing, we might need to know which arguments were used in this
* group.
*
- * Sure, we could just use {@link Command#arguments}, but that would mean that we would have to iterate through all
- * the arguments in there for filtering ours, which is probably worse.
+ * Sure, we could just use {@link Command#getArguments()}, but that would mean that we would have
+ * to iterate through all the arguments in there for filtering ours, which is probably worse.
*/
private final @NotNull List<@NotNull Argument, ?>> arguments = new ArrayList<>();
@@ -274,6 +274,7 @@ public ArgumentGroup getParent() {
@Override
public boolean equals(@NotNull Object obj) {
+ if (obj == this) return true;
if (obj instanceof ArgumentGroup group)
return this.parentCommand == group.parentCommand && this.name.equals(group.name);
return false;
diff --git a/src/main/java/lanat/ArgumentGroupAdder.java b/src/main/java/lanat/ArgumentGroupAdder.java
index f9cda9d8..6f568dda 100644
--- a/src/main/java/lanat/ArgumentGroupAdder.java
+++ b/src/main/java/lanat/ArgumentGroupAdder.java
@@ -24,7 +24,7 @@ public interface ArgumentGroupAdder extends NamedWithDescription {
@NotNull List<@NotNull ArgumentGroup> getGroups();
/**
- * Checks that all the argument groups in this container have unique names.
+ * Checks that all the argument groups in this container are unique.
* @throws ArgumentGroupAlreadyExistsException if there are two argument groups with the same name
*/
default void checkUniqueGroups() {
diff --git a/src/main/java/lanat/ArgumentParser.java b/src/main/java/lanat/ArgumentParser.java
index 14d0368c..25ff4314 100644
--- a/src/main/java/lanat/ArgumentParser.java
+++ b/src/main/java/lanat/ArgumentParser.java
@@ -4,10 +4,12 @@
import lanat.exceptions.IncompatibleCommandTemplateType;
import lanat.parsing.TokenType;
import lanat.parsing.errors.ErrorHandler;
+import lanat.utils.UtlMisc;
import lanat.utils.UtlReflection;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Arrays;
@@ -131,7 +133,11 @@ public static ArgumentParser from(@NotNull Class extends CommandTemplate> temp
*/
public static
@NotNull T parseFromInto(@NotNull Class templateClass, @NotNull CLInput input) {
- return ArgumentParser.parseFromInto(templateClass, input, opts -> opts.printErrors().exitIfErrors());
+ return ArgumentParser.parseFromInto(
+ templateClass,
+ input,
+ opts -> opts.printErrors().exitIfErrors().printHelpIfNoInput().exitIfNoInput()
+ );
}
/**
@@ -191,7 +197,7 @@ public static ArgumentParser from(@NotNull Class extends CommandTemplate> temp
return new ParsedArgumentsRoot(
this,
this.getParser().getParsedArgumentsHashMap(),
- this.subCommands.stream().map(Command::getParsedArguments).toList(),
+ this.getCommands().stream().map(Command::getParsedArguments).toList(),
this.getForwardValue()
);
}
@@ -239,7 +245,9 @@ public void setVersion(@NotNull String version) {
*/
public void addVersionArgument() {
this.addArgument(Argument.createOfBoolType("version")
- .onOk(t -> System.out.println("Version: " + this.getVersion()))
+ .onOk(t ->
+ System.out.println("Version: " + UtlMisc.nonNullOrElse(this.getVersion(), "unknown"))
+ )
.withDescription("Shows the version of this program.")
.allowsUnique()
);
@@ -366,7 +374,7 @@ private static T into(
// get the name of the argument from the annotation or field name
final String argName = annotation.names().length == 0 ? f.getName() : annotation.names()[0];
- final @NotNull Optional
* @param The type of the argument type used to parse the values.
* @param The type of the values.
+ * @see HashMap
*/
public class KeyValuesArgumentType, Ts> extends ArgumentType> {
private final @NotNull ArgumentType valueType;
diff --git a/src/main/java/lanat/argumentTypes/LongArgumentType.java b/src/main/java/lanat/argumentTypes/LongArgumentType.java
index bef388e8..25e4cc23 100644
--- a/src/main/java/lanat/argumentTypes/LongArgumentType.java
+++ b/src/main/java/lanat/argumentTypes/LongArgumentType.java
@@ -7,6 +7,7 @@
/**
* An argument type that takes a long integer number.
+ * @see Long
*/
public class LongArgumentType extends NumberArgumentType {
@Override
diff --git a/src/main/java/lanat/argumentTypes/MultipleNumbersArgumentType.java b/src/main/java/lanat/argumentTypes/MultipleNumbersArgumentType.java
new file mode 100644
index 00000000..cafe72de
--- /dev/null
+++ b/src/main/java/lanat/argumentTypes/MultipleNumbersArgumentType.java
@@ -0,0 +1,28 @@
+package lanat.argumentTypes;
+
+import lanat.ArgumentType;
+import lanat.ArgumentTypeInfer;
+import lanat.utils.Range;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * An argument type that takes multiple numbers.
+ * @param The type of number that this argument type is.
+ */
+public class MultipleNumbersArgumentType extends TupleArgumentType {
+ /**
+ * Creates a new {@link TupleArgumentType} with the specified range of values that the argument will take.
+ * @param range The range of values that the argument will take.
+ * @param defaultValue The default value of the argument. This will be used if no values are provided.
+ * @throws lanat.exceptions.ArgumentTypeInferException If the type of the default value is not supported.
+ */
+ @SuppressWarnings("unchecked")
+ public MultipleNumbersArgumentType(@NotNull Range range, @NotNull Ti[] defaultValue) {
+ super(
+ range,
+ // we can infer the type of the argument type from the default value
+ (ArgumentType)ArgumentTypeInfer.get(defaultValue.getClass().getComponentType()),
+ defaultValue
+ );
+ }
+}
diff --git a/src/main/java/lanat/argumentTypes/MultipleStringsArgumentType.java b/src/main/java/lanat/argumentTypes/MultipleStringsArgumentType.java
index 291c46b4..c19af4c5 100644
--- a/src/main/java/lanat/argumentTypes/MultipleStringsArgumentType.java
+++ b/src/main/java/lanat/argumentTypes/MultipleStringsArgumentType.java
@@ -1,26 +1,23 @@
package lanat.argumentTypes;
-import lanat.ArgumentType;
import lanat.utils.Range;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
/**
* An argument type that takes multiple strings.
*/
-public class MultipleStringsArgumentType extends ArgumentType {
- @Override
- public @NotNull Range getRequiredArgValueCount() {
- return Range.AT_LEAST_ONE;
+public class MultipleStringsArgumentType extends TupleArgumentType {
+ /**
+ * Creates a new {@link TupleArgumentType} with the specified range of values that the argument will take.
+ * @param range The range of values that the argument will take.
+ */
+ public MultipleStringsArgumentType(@NotNull Range range) {
+ super(range, new StringArgumentType(), new String[0]);
}
+ // no need for anything fancy here, simply return the args
@Override
public @NotNull String[] parseValues(@NotNull String @NotNull [] args) {
return args;
}
-
- @Override
- public @Nullable String getDescription() {
- return "Accepts multiple strings.";
- }
}
diff --git a/src/main/java/lanat/argumentTypes/NumberArgumentType.java b/src/main/java/lanat/argumentTypes/NumberArgumentType.java
index 0445ff3a..7f887f3d 100644
--- a/src/main/java/lanat/argumentTypes/NumberArgumentType.java
+++ b/src/main/java/lanat/argumentTypes/NumberArgumentType.java
@@ -10,6 +10,7 @@
* of {@link #parseValues(String[])} that will parse the first argument as a number using the
* function returned by {@link #getParseFunction()}.
* @param The type of number that this argument type is.
+ * @see Number
*/
public abstract class NumberArgumentType extends ArgumentType {
/**
diff --git a/src/main/java/lanat/argumentTypes/NumberRangeArgumentType.java b/src/main/java/lanat/argumentTypes/NumberRangeArgumentType.java
index 78cca4ee..1c876e19 100644
--- a/src/main/java/lanat/argumentTypes/NumberRangeArgumentType.java
+++ b/src/main/java/lanat/argumentTypes/NumberRangeArgumentType.java
@@ -1,7 +1,7 @@
package lanat.argumentTypes;
import lanat.ArgumentType;
-import lanat.utils.UtlReflection;
+import lanat.ArgumentTypeInfer;
import lanat.utils.displayFormatter.Color;
import lanat.utils.displayFormatter.TextFormatter;
import org.jetbrains.annotations.NotNull;
@@ -17,19 +17,19 @@ public class NumberRangeArgumentType> extends A
private final ArgumentType argumentType;
private final T min, max;
+ /**
+ * Creates a new number range argument type.
+ * @param min The minimum value.
+ * @param max The maximum value.
+ * @throws lanat.exceptions.ArgumentTypeInferException If the type of the default value is not supported.
+ */
@SuppressWarnings("unchecked")
public NumberRangeArgumentType(@NotNull T min, @NotNull T max) {
if (min.compareTo(max) > 0) {
throw new IllegalArgumentException("min must be less than or equal to max");
}
- final var typeInferred = ArgumentType.getTypeInfer(min.getClass());
-
- if (typeInferred == null) {
- throw new IllegalArgumentException("Unsupported type: " + min.getClass().getName());
- }
-
- this.argumentType = (ArgumentType)UtlReflection.instantiate(typeInferred);
+ this.argumentType = (ArgumentType)ArgumentTypeInfer.get(min.getClass());
this.registerSubType(this.argumentType);
this.min = min;
diff --git a/src/main/java/lanat/argumentTypes/ShortArgumentType.java b/src/main/java/lanat/argumentTypes/ShortArgumentType.java
index 529d419c..4ed67dda 100644
--- a/src/main/java/lanat/argumentTypes/ShortArgumentType.java
+++ b/src/main/java/lanat/argumentTypes/ShortArgumentType.java
@@ -7,6 +7,7 @@
/**
* An argument type that takes a short integer number.
+ * @see Short
*/
public class ShortArgumentType extends NumberArgumentType {
@Override
diff --git a/src/main/java/lanat/argumentTypes/StringArgumentType.java b/src/main/java/lanat/argumentTypes/StringArgumentType.java
index 1f04a3c0..957a0b13 100644
--- a/src/main/java/lanat/argumentTypes/StringArgumentType.java
+++ b/src/main/java/lanat/argumentTypes/StringArgumentType.java
@@ -7,6 +7,7 @@
/**
* An argument type that takes a string of characters.
+ * @see String
*/
public class StringArgumentType extends ArgumentType {
@Override
diff --git a/src/main/java/lanat/argumentTypes/TupleArgumentType.java b/src/main/java/lanat/argumentTypes/TupleArgumentType.java
index 4b95155a..73d52b51 100644
--- a/src/main/java/lanat/argumentTypes/TupleArgumentType.java
+++ b/src/main/java/lanat/argumentTypes/TupleArgumentType.java
@@ -12,12 +12,32 @@
* Shows a properly formatted description and representation.
* @param the type of the value that the argument will take
*/
-public abstract class TupleArgumentType extends ArgumentType {
+public abstract class TupleArgumentType extends ArgumentType {
private final @NotNull Range argCount;
+ private final @NotNull ArgumentType argumentType;
- public TupleArgumentType(@NotNull Range range, @NotNull T initialValue) {
- super(initialValue);
+ /**
+ * Creates a new {@link TupleArgumentType} with the specified range and argument type.
+ * @param range The range of values that the argument will take.
+ * @param argumentType The argument type that will be used to parse the values.
+ * @param defaultValue The default value of the argument. This will be used if no values are provided.
+ */
+ public TupleArgumentType(@NotNull Range range, @NotNull ArgumentType argumentType, @NotNull T[] defaultValue) {
+ super(defaultValue);
this.argCount = range;
+ this.registerSubType(this.argumentType = argumentType);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public T @Nullable [] parseValues(@NotNull String... args) {
+ var result = new Object[args.length];
+
+ for (int i = 0; i < args.length; i++) {
+ result[i] = this.argumentType.parseValues(args[i]);
+ }
+
+ return (T[])result;
}
@Override
@@ -26,14 +46,18 @@ public TupleArgumentType(@NotNull Range range, @NotNull T initialValue) {
}
@Override
- public @NotNull TextFormatter getRepresentation() {
- return new TextFormatter(this.getValue().getClass().getSimpleName())
+ public @Nullable TextFormatter getRepresentation() {
+ var argTypeRepr = this.argumentType.getRepresentation();
+ if (argTypeRepr == null)
+ return null;
+
+ return argTypeRepr
.concat(new TextFormatter(this.argCount.getRegexRange()).withForegroundColor(Color.BRIGHT_YELLOW));
}
@Override
public @Nullable String getDescription() {
return "Takes " + this.argCount.getMessage("value")
- + " of type " + this.getInitialValue().getClass().getSimpleName() + ".";
+ + " of type " + this.argumentType.getRepresentation() + ".";
}
}
\ No newline at end of file
diff --git a/src/main/java/lanat/exceptions/ArgumentTypeInferException.java b/src/main/java/lanat/exceptions/ArgumentTypeInferException.java
new file mode 100644
index 00000000..9e67177f
--- /dev/null
+++ b/src/main/java/lanat/exceptions/ArgumentTypeInferException.java
@@ -0,0 +1,7 @@
+package lanat.exceptions;
+
+public class ArgumentTypeInferException extends ArgumentTypeException {
+ public ArgumentTypeInferException(Class> clazz) {
+ super("No argument type found for type: " + clazz.getName());
+ }
+}
diff --git a/src/main/java/lanat/exceptions/ObjectAlreadyExistsException.java b/src/main/java/lanat/exceptions/ObjectAlreadyExistsException.java
index b115b2a8..8eda309c 100644
--- a/src/main/java/lanat/exceptions/ObjectAlreadyExistsException.java
+++ b/src/main/java/lanat/exceptions/ObjectAlreadyExistsException.java
@@ -2,7 +2,6 @@
import lanat.NamedWithDescription;
import lanat.utils.UtlReflection;
-import lanat.utils.UtlString;
import org.jetbrains.annotations.NotNull;
/**
@@ -17,12 +16,9 @@ public ObjectAlreadyExistsException(
{
super(
typeName
- + " "
- + UtlString.surround(obj.getName())
- + " already exists in "
+ + " '" + obj.getName() + "' already exists in "
+ UtlReflection.getSimpleName(container.getClass())
- + " "
- + UtlString.surround(container.getName())
+ + " '" + container.getName() + "'"
);
}
}
diff --git a/src/main/java/lanat/exceptions/ObjectNotFoundException.java b/src/main/java/lanat/exceptions/ObjectNotFoundException.java
index 8b888995..b0bc84a1 100644
--- a/src/main/java/lanat/exceptions/ObjectNotFoundException.java
+++ b/src/main/java/lanat/exceptions/ObjectNotFoundException.java
@@ -2,7 +2,6 @@
import lanat.NamedWithDescription;
import lanat.utils.UtlReflection;
-import lanat.utils.UtlString;
import org.jetbrains.annotations.NotNull;
/**
@@ -17,12 +16,9 @@ public ObjectNotFoundException(
{
super(
typeName
- + " "
- + UtlString.surround(obj.getName())
- + " was not found in "
+ + " '" + obj.getName() + "' was not found in "
+ UtlReflection.getSimpleName(container.getClass())
- + " "
- + UtlString.surround(container.getName())
+ + " '" + container.getName() + "'"
);
}
@@ -31,8 +27,6 @@ public ObjectNotFoundException(@NotNull String typeName, @NotNull NamedWithDescr
}
public ObjectNotFoundException(@NotNull String typeName, @NotNull String name) {
- super(
- typeName + " " + UtlString.surround(name) + " was not found"
- );
+ super(typeName + " '" + name + "' was not found");
}
}
diff --git a/src/main/java/lanat/helpRepresentation/ArgumentRepr.java b/src/main/java/lanat/helpRepresentation/ArgumentRepr.java
index a8bd1325..f348d4af 100644
--- a/src/main/java/lanat/helpRepresentation/ArgumentRepr.java
+++ b/src/main/java/lanat/helpRepresentation/ArgumentRepr.java
@@ -2,6 +2,7 @@
import lanat.Argument;
import lanat.helpRepresentation.descriptions.DescriptionFormatter;
+import lanat.utils.UtlMisc;
import lanat.utils.displayFormatter.FormatOption;
import lanat.utils.displayFormatter.TextFormatter;
import org.jetbrains.annotations.NotNull;
@@ -64,12 +65,10 @@ private ArgumentRepr() {}
* @return the representation and description of the argument
*/
public static @Nullable String getDescription(@NotNull Argument, ?> arg) {
- final String desc = DescriptionFormatter.parse(arg);
-
- if (desc == null)
- return null;
-
- return ArgumentRepr.getRepresentation(arg) + ":\n" + HelpFormatter.indent(desc, arg);
+ return UtlMisc.nullOrElse(
+ DescriptionFormatter.parse(arg),
+ desc -> ArgumentRepr.getRepresentation(arg) + ":\n" + HelpFormatter.indent(desc, arg)
+ );
}
/**
diff --git a/src/main/java/lanat/helpRepresentation/CommandRepr.java b/src/main/java/lanat/helpRepresentation/CommandRepr.java
index 5d2d31b4..4cdcb7da 100644
--- a/src/main/java/lanat/helpRepresentation/CommandRepr.java
+++ b/src/main/java/lanat/helpRepresentation/CommandRepr.java
@@ -2,6 +2,7 @@
import lanat.Command;
import lanat.helpRepresentation.descriptions.DescriptionFormatter;
+import lanat.utils.UtlMisc;
import lanat.utils.displayFormatter.FormatOption;
import lanat.utils.displayFormatter.TextFormatter;
import org.jetbrains.annotations.NotNull;
@@ -52,11 +53,10 @@ private CommandRepr() {}
* @return the parsed description of the command
*/
public static @Nullable String getDescription(@NotNull Command cmd) {
- final String desc = DescriptionFormatter.parse(cmd);
-
- return desc == null
- ? null
- : CommandRepr.getRepresentation(cmd) + ":\n" + HelpFormatter.indent(desc, cmd);
+ return UtlMisc.nullOrElse(
+ DescriptionFormatter.parse(cmd),
+ desc -> CommandRepr.getRepresentation(cmd) + ":\n" + HelpFormatter.indent(desc, cmd)
+ );
}
/**
diff --git a/src/main/java/lanat/helpRepresentation/HelpFormatter.java b/src/main/java/lanat/helpRepresentation/HelpFormatter.java
index 72ea7dd7..77691117 100644
--- a/src/main/java/lanat/helpRepresentation/HelpFormatter.java
+++ b/src/main/java/lanat/helpRepresentation/HelpFormatter.java
@@ -20,7 +20,7 @@
* returns a string.
*
*
- * To generate the help message, use {@link #generate(Command)} ()}.
+ * To generate the help message, use {@link #generate(Command)}.
*
*
* @see LayoutItem
@@ -32,6 +32,7 @@ public class HelpFormatter {
public static boolean debugLayout = false;
static {
+ // register the default tags before we start parsing descriptions
Tag.initTags();
}
diff --git a/src/main/java/lanat/helpRepresentation/LayoutGenerators.java b/src/main/java/lanat/helpRepresentation/LayoutGenerators.java
index bd3678df..f1951a64 100644
--- a/src/main/java/lanat/helpRepresentation/LayoutGenerators.java
+++ b/src/main/java/lanat/helpRepresentation/LayoutGenerators.java
@@ -77,7 +77,7 @@ private LayoutGenerators() {}
}
if (!cmd.getCommands().isEmpty())
- buffer.append(' ').append(CommandRepr.getSubCommandsRepresentation(cmd));
+ buffer.append(CommandRepr.getSubCommandsRepresentation(cmd));
return buffer.toString();
}
diff --git a/src/main/java/lanat/helpRepresentation/LayoutItem.java b/src/main/java/lanat/helpRepresentation/LayoutItem.java
index 97bf1df8..9abef01e 100644
--- a/src/main/java/lanat/helpRepresentation/LayoutItem.java
+++ b/src/main/java/lanat/helpRepresentation/LayoutItem.java
@@ -10,7 +10,7 @@
/**
* Represents a layout item in the help message generated by {@link HelpFormatter}. This class is essentially just a
- * builder with some helper commands for setting a {@link Function} that generates a {@link String} for a given
+ * builder with some helper utilities for setting a {@link Function} that generates a {@link String} for a given
* {@link Command}.
*
* @see HelpFormatter
@@ -107,9 +107,10 @@ public LayoutItem margin(int margin) {
*
* It is shown as:
*
- * <title<:
+ * <title>:
* <content>
*
+ * If no content is generated, the title is not shown.
*
* @param title the title of the layout item
*/
diff --git a/src/main/java/lanat/helpRepresentation/descriptions/DescriptionFormatter.java b/src/main/java/lanat/helpRepresentation/descriptions/DescriptionFormatter.java
index 5c784b2c..03221581 100644
--- a/src/main/java/lanat/helpRepresentation/descriptions/DescriptionFormatter.java
+++ b/src/main/java/lanat/helpRepresentation/descriptions/DescriptionFormatter.java
@@ -3,6 +3,7 @@
import lanat.CommandUser;
import lanat.NamedWithDescription;
import lanat.helpRepresentation.descriptions.exceptions.MalformedTagException;
+import lanat.utils.UtlMisc;
import lanat.utils.UtlString;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -70,11 +71,10 @@ private DescriptionFormatter() {}
*/
public static
@Nullable String parse(@NotNull T element) {
- final var desc = element.getDescription();
- if (desc == null)
- return null;
-
- return DescriptionFormatter.parse(element, desc);
+ return UtlMisc.nullOrElse(
+ element.getDescription(),
+ desc -> DescriptionFormatter.parse(element, desc)
+ );
}
/**
diff --git a/src/main/java/lanat/helpRepresentation/descriptions/Tag.java b/src/main/java/lanat/helpRepresentation/descriptions/Tag.java
index 212e6c03..80e94596 100644
--- a/src/main/java/lanat/helpRepresentation/descriptions/Tag.java
+++ b/src/main/java/lanat/helpRepresentation/descriptions/Tag.java
@@ -7,7 +7,6 @@
import lanat.helpRepresentation.descriptions.tags.FormatTag;
import lanat.helpRepresentation.descriptions.tags.LinkTag;
import lanat.utils.UtlReflection;
-import lanat.utils.UtlString;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -53,7 +52,7 @@ public static String getTagNameFromTagClass(Class extends Tag> tagClass) {
.findFirst()
.map(Map.Entry::getKey)
.orElseThrow(() ->
- new IllegalStateException("Tag class " + UtlString.surround(tagClass.getName()) + " is not registered")
+ new IllegalStateException("Tag class '" + tagClass.getName() + "' is not registered")
);
}
diff --git a/src/main/java/lanat/helpRepresentation/descriptions/exceptions/InvalidRouteException.java b/src/main/java/lanat/helpRepresentation/descriptions/exceptions/InvalidRouteException.java
index 42adf705..f594f2db 100644
--- a/src/main/java/lanat/helpRepresentation/descriptions/exceptions/InvalidRouteException.java
+++ b/src/main/java/lanat/helpRepresentation/descriptions/exceptions/InvalidRouteException.java
@@ -3,7 +3,6 @@
import lanat.NamedWithDescription;
import lanat.exceptions.LanatException;
import lanat.utils.UtlReflection;
-import lanat.utils.UtlString;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -15,8 +14,8 @@ public InvalidRouteException(@NotNull NamedWithDescription user, @Nullable Strin
public InvalidRouteException(@NotNull NamedWithDescription user, @Nullable String value, @Nullable String message) {
super(
- "invalid route value " + UtlString.surround(value)
- + " for " + UtlReflection.getSimpleName(user.getClass()) + " " + UtlString.surround(user.getName())
+ "invalid route value '" + value + "' for "
+ + UtlReflection.getSimpleName(user.getClass()) + " '" + user.getName() + "'"
+ (message == null ? "" : ": " + message)
);
}
diff --git a/src/main/java/lanat/helpRepresentation/descriptions/exceptions/MalformedTagException.java b/src/main/java/lanat/helpRepresentation/descriptions/exceptions/MalformedTagException.java
index cd8064c3..bd8105e5 100644
--- a/src/main/java/lanat/helpRepresentation/descriptions/exceptions/MalformedTagException.java
+++ b/src/main/java/lanat/helpRepresentation/descriptions/exceptions/MalformedTagException.java
@@ -2,7 +2,6 @@
import lanat.exceptions.LanatException;
import lanat.helpRepresentation.descriptions.Tag;
-import lanat.utils.UtlString;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -10,9 +9,7 @@
public class MalformedTagException extends LanatException {
public MalformedTagException(@NotNull Class extends Tag> tagClass, @Nullable String reason) {
super(
- "Tag "
- + UtlString.surround(Tag.getTagNameFromTagClass(tagClass))
- + " is malformed"
+ "Tag '" + Tag.getTagNameFromTagClass(tagClass) + "' is malformed"
+ (reason == null ? "" : ": " + reason)
);
}
diff --git a/src/main/java/lanat/helpRepresentation/descriptions/exceptions/NoDescriptionDefinedException.java b/src/main/java/lanat/helpRepresentation/descriptions/exceptions/NoDescriptionDefinedException.java
index afdb1d00..a0188ba2 100644
--- a/src/main/java/lanat/helpRepresentation/descriptions/exceptions/NoDescriptionDefinedException.java
+++ b/src/main/java/lanat/helpRepresentation/descriptions/exceptions/NoDescriptionDefinedException.java
@@ -3,7 +3,6 @@
import lanat.NamedWithDescription;
import lanat.exceptions.LanatException;
import lanat.utils.UtlReflection;
-import lanat.utils.UtlString;
import org.jetbrains.annotations.NotNull;
/** Thrown when a description was not defined for an object. */
@@ -11,7 +10,7 @@ public class NoDescriptionDefinedException extends LanatException {
public NoDescriptionDefinedException(@NotNull NamedWithDescription user) {
super(
"No description defined for "
- + UtlReflection.getSimpleName(user.getClass()) + " " + UtlString.surround(user.getName())
+ + UtlReflection.getSimpleName(user.getClass()) + " '" + user.getName() + "'"
);
}
}
diff --git a/src/main/java/lanat/helpRepresentation/descriptions/exceptions/UnknownTagException.java b/src/main/java/lanat/helpRepresentation/descriptions/exceptions/UnknownTagException.java
index ee6173fb..0773ccc4 100644
--- a/src/main/java/lanat/helpRepresentation/descriptions/exceptions/UnknownTagException.java
+++ b/src/main/java/lanat/helpRepresentation/descriptions/exceptions/UnknownTagException.java
@@ -1,12 +1,11 @@
package lanat.helpRepresentation.descriptions.exceptions;
import lanat.exceptions.LanatException;
-import lanat.utils.UtlString;
import org.jetbrains.annotations.NotNull;
/** Thrown when a tag with an unknown name is attempted to be used. */
public class UnknownTagException extends LanatException {
public UnknownTagException(@NotNull String tagName) {
- super("tag " + UtlString.surround(tagName) + " does not exist");
+ super("tag '" + tagName + "' does not exist");
}
}
diff --git a/src/main/java/lanat/helpRepresentation/descriptions/tags/ColorTag.java b/src/main/java/lanat/helpRepresentation/descriptions/tags/ColorTag.java
index df96a573..5089aa62 100644
--- a/src/main/java/lanat/helpRepresentation/descriptions/tags/ColorTag.java
+++ b/src/main/java/lanat/helpRepresentation/descriptions/tags/ColorTag.java
@@ -55,8 +55,7 @@ public class ColorTag extends Tag {
final String[] split = UtlString.split(value, ':');
if (split.length != 2)
throw new MalformedTagException(
- ColorTag.class, "invalid color format " + UtlString.surround(value)
- + " (expected format: 'foreground:background')"
+ ColorTag.class, "invalid color format '" + value + "' (expected format: 'foreground:background')"
);
return ColorTag.getColor(split[0]).fg() + ColorTag.getColor(split[1]).bg();
@@ -80,7 +79,7 @@ private static Color getColor(@NotNull String colorName) {
case "dark magenta", "dm" -> Color.MAGENTA;
case "dark cyan", "dc" -> Color.CYAN;
case "dark white", "dw" -> Color.WHITE;
- default -> throw new MalformedTagException(ColorTag.class, "unknown color name " + UtlString.surround(colorName));
+ default -> throw new MalformedTagException(ColorTag.class, "unknown color name '" + colorName + "'");
};
}
}
diff --git a/src/main/java/lanat/helpRepresentation/descriptions/tags/FormatTag.java b/src/main/java/lanat/helpRepresentation/descriptions/tags/FormatTag.java
index 0674a667..01068569 100644
--- a/src/main/java/lanat/helpRepresentation/descriptions/tags/FormatTag.java
+++ b/src/main/java/lanat/helpRepresentation/descriptions/tags/FormatTag.java
@@ -62,7 +62,7 @@ private static FormatOption getFormat(@NotNull String formatName) {
case "hidden", "h" -> FormatOption.HIDDEN;
case "strike", "s" -> FormatOption.STRIKE_THROUGH;
default ->
- throw new MalformedTagException(FormatTag.class, "unknown format name " + UtlString.surround(formatName));
+ throw new MalformedTagException(FormatTag.class, "unknown format name '" + formatName + "'");
};
}
}
diff --git a/src/main/java/lanat/parsing/Parser.java b/src/main/java/lanat/parsing/Parser.java
index d7a0a7f8..ea05bc96 100644
--- a/src/main/java/lanat/parsing/Parser.java
+++ b/src/main/java/lanat/parsing/Parser.java
@@ -81,8 +81,12 @@ public void setTokens(@NotNull List<@NotNull Token> tokens) {
this.tokens = tokens;
}
+ /**
+ * Parses the tokens that have been set. Delegates parsing of argument values to the {@link ArgumentType} of the
+ * argument that is being parsed.
+ */
public void parseTokens() {
- assert this.tokens != null : "Tokens have not been set yet";
+ assert this.tokens != null : "Tokens have not been set yet.";
assert !this.hasFinished : "This parser has already finished parsing.";
// number of positional arguments that have been parsed.
diff --git a/src/main/java/lanat/parsing/Tokenizer.java b/src/main/java/lanat/parsing/Tokenizer.java
index 0e4726e8..0397ac40 100644
--- a/src/main/java/lanat/parsing/Tokenizer.java
+++ b/src/main/java/lanat/parsing/Tokenizer.java
@@ -54,10 +54,16 @@ private void setInputString(@NotNull String inputString) {
* {@link Tokenizer#getFinalTokens()}
*/
public void tokenize(@NotNull String input) {
- assert !this.hasFinished : "Tokenizer has already finished tokenizing";
+ assert !this.hasFinished : "Tokenizer has already finished tokenizing.";
this.setInputString(input);
+ // nothing to tokenize. Just finish
+ if (input.isEmpty()) {
+ this.hasFinished = true;
+ return;
+ }
+
char currentStringChar = 0; // the character that opened the string
TokenizeError.TokenizeErrorType errorType = null;
diff --git a/src/main/java/lanat/utils/UtlMisc.java b/src/main/java/lanat/utils/UtlMisc.java
index c7af99f7..f6775495 100644
--- a/src/main/java/lanat/utils/UtlMisc.java
+++ b/src/main/java/lanat/utils/UtlMisc.java
@@ -2,8 +2,8 @@
import lanat.CommandUser;
import lanat.MultipleNamesAndDescription;
-import lanat.exceptions.ObjectAlreadyExistsException;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.function.Function;
@@ -19,7 +19,7 @@ private UtlMisc() {}
*/
public static void requireUniqueElements(
@NotNull List list,
- @NotNull Function exceptionSupplier
+ @NotNull Function exceptionSupplier
) {
for (int i = 0; i < list.size(); i++) {
final var el = list.get(i);
@@ -44,4 +44,27 @@ public static void requireUniqueElements(
boolean equalsByNamesAndParentCmd(@NotNull T a, @NotNull T b) {
return a.getParentCommand() == b.getParentCommand() && a.getNames().stream().anyMatch(b::hasName);
}
+
+ /**
+ * Returns {@code obj} if it is not {@code null}, otherwise returns {@code defaultObj}.
+ * @param obj The object to check
+ * @param defaultObj The object to return if {@code obj} is {@code null}
+ * @return {@code obj} if it is not {@code null}, otherwise returns {@code defaultObj}
+ * @param The type of the objects
+ */
+ public static @NotNull T nonNullOrElse(@Nullable T obj, @NotNull T defaultObj) {
+ return obj == null ? defaultObj : obj;
+ }
+
+ /**
+ * Returns {@code null} if {@code obj} is {@code null}, otherwise returns the result of the given function.
+ * @param obj The object to check
+ * @param defaultObj The function to apply to {@code obj} if it is not {@code null}
+ * @return {@code null} if {@code obj} is {@code null}, otherwise returns the result of the given function
+ * @param The type of the objects
+ * @param The type of the result of the function
+ */
+ public static @Nullable R nullOrElse(@Nullable T obj, @NotNull Function<@NotNull T, @NotNull R> defaultObj) {
+ return obj == null ? null : defaultObj.apply(obj);
+ }
}
diff --git a/src/main/java/lanat/utils/UtlReflection.java b/src/main/java/lanat/utils/UtlReflection.java
index a1e8714e..bc6800df 100644
--- a/src/main/java/lanat/utils/UtlReflection.java
+++ b/src/main/java/lanat/utils/UtlReflection.java
@@ -2,6 +2,7 @@
import org.jetbrains.annotations.NotNull;
+import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.stream.Stream;
@@ -48,7 +49,24 @@ public static boolean hasParameters(Method method, Class>... parameters) {
public static T instantiate(Class clazz, Object... args) {
try {
return clazz.getDeclaredConstructor().newInstance(args);
- } catch (ReflectiveOperationException e) {
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException("Unable to find a public constructor for the class '" + clazz.getName()
+ + """
+ '. Please, make sure:
+ - This class has a public constructor with no arguments. (Or no constructor at all)
+ - This is a static class. (Not an inner class)"""
+ );
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(
+ "Unable to gain access to the class '" + clazz.getName()
+ + "'. Please, make sure this class is visible to Lanat."
+ );
+ } catch (InstantiationException e) {
+ throw new RuntimeException(
+ "Unable to instantiate the class '" + clazz.getName()
+ + "'. Please, make sure this class is not abstract."
+ );
+ } catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
@@ -64,5 +82,4 @@ public static Stream getMethods(Class> clazz) {
return UtlReflection.getMethods(clazz.getSuperclass());
return Stream.of(clazz.getDeclaredMethods());
}
-
}
diff --git a/src/main/java/lanat/utils/UtlString.java b/src/main/java/lanat/utils/UtlString.java
index ab91ece4..0965714c 100644
--- a/src/main/java/lanat/utils/UtlString.java
+++ b/src/main/java/lanat/utils/UtlString.java
@@ -72,7 +72,7 @@ private UtlString() {}
final var indentBuff = new StringBuilder(); // buffer for the current indentation that will be added to the beginning of each line if needed
int lineWidth = 0; // the current line width
- boolean jumped = true; // true if a newline was added. starts off as true in case the string with indentation
+ boolean jumped = true; // true if a newline was added. starts off as true in case the string starts with indentation
for (char chr : str.toCharArray()) {
if (chr == ' ' || chr == '\t') {
@@ -89,7 +89,7 @@ private UtlString() {}
}
endBuffer.append(wordBuff).append(chr);
// make sure to not count escape sequences on the length!
- lineWidth += UtlString.removeSequences(wordBuff.toString()).length() + 1;
+ lineWidth += UtlString.removeSequences(wordBuff.toString()).length() + 1; // +1 for the char we just added
wordBuff.setLength(0);
}
diff --git a/src/test/java/lanat/test/TestingParser.java b/src/test/java/lanat/test/TestingParser.java
index c0f70263..eb5a3cfb 100644
--- a/src/test/java/lanat/test/TestingParser.java
+++ b/src/test/java/lanat/test/TestingParser.java
@@ -28,7 +28,7 @@ public List parseGetErrors(String args) {
}
public @NotNull ParsedArgumentsRoot parseGetValues(@NotNull String args) {
- var res = this.parse(CLInput.from(args)).getParsedArguments();
+ var res = this.parse(CLInput.from(args)).printErrors().getParsedArguments();
assertNotNull(res, "The result of the parsing was null (Arguments have failed)");
return res;
}
diff --git a/src/test/java/lanat/test/UnitTests.java b/src/test/java/lanat/test/UnitTests.java
index 4f4c308c..65f3c366 100644
--- a/src/test/java/lanat/test/UnitTests.java
+++ b/src/test/java/lanat/test/UnitTests.java
@@ -6,7 +6,6 @@
import lanat.argumentTypes.CounterArgumentType;
import lanat.argumentTypes.IntegerArgumentType;
import lanat.argumentTypes.StringArgumentType;
-import lanat.argumentTypes.TupleArgumentType;
import lanat.helpRepresentation.HelpFormatter;
import lanat.utils.Range;
import lanat.utils.displayFormatter.TextFormatter;
@@ -17,9 +16,10 @@
import static org.junit.jupiter.api.Assertions.assertTrue;
-class StringJoiner extends TupleArgumentType {
- public StringJoiner() {
- super(Range.from(1).to(3), "");
+class StringJoiner extends ArgumentType {
+ @Override
+ public @NotNull Range getRequiredArgValueCount() {
+ return Range.from(1).to(3);
}
@Override
diff --git a/src/test/java/lanat/test/manualTests/CommandTemplateExample.java b/src/test/java/lanat/test/manualTests/CommandTemplateExample.java
index e3114f89..c91fde58 100644
--- a/src/test/java/lanat/test/manualTests/CommandTemplateExample.java
+++ b/src/test/java/lanat/test/manualTests/CommandTemplateExample.java
@@ -4,12 +4,10 @@
import lanat.ArgumentGroup;
import lanat.Command;
import lanat.CommandTemplate;
-import lanat.argumentTypes.CounterArgumentType;
-import lanat.argumentTypes.NumberRangeArgumentType;
-import lanat.argumentTypes.StdinArgumentType;
-import lanat.argumentTypes.StringArgumentType;
+import lanat.argumentTypes.*;
import org.jetbrains.annotations.NotNull;
+import java.io.File;
import java.util.Optional;
@Command.Define(names = "my-program", description = "This is a test program.")
@@ -28,10 +26,14 @@ public CommandTemplateExample() {}
@Argument.Define(names = "arg1", argType = StringArgumentType.class)
public String arg1;
+ @Argument.Define(description = "")
+ public File file;
@Argument.Define(names = "arg1a", argType = StringArgumentType.class)
public String arg1copy;
+ @Argument.Define
+ public Byte[] bytes;
@CommandAccessor
public MySubCommand subCommand;
@@ -40,11 +42,26 @@ public CommandTemplateExample() {}
public static void beforeInit(@NotNull CommandBuildHelper helper) {
helper., Double>arg("number")
.withArgType(new NumberRangeArgumentType<>(5.5, 15.89));
+ helper.arg("file")
+ .withArgType(new FileArgumentType(true, FileArgumentType.FileType.REGULAR_FILE) {
+ @Override
+ protected boolean checkFile(@NotNull File file) {
+ if (!super.checkFile(file)) return false;
+
+ if (!file.canExecute()) {
+ this.addError("File is not executable.");
+ return false;
+ }
+
+ return true;
+ }
+ });
}
@InitDef
public static void afterInit(@NotNull Command cmd) {
cmd.addGroup(new ArgumentGroup("test-group") {{
+ this.setExclusive(true);
this.addArgument(cmd.getArgument("string"));
this.addArgument(cmd.getArgument("number"));
}});
@@ -52,7 +69,7 @@ public static void afterInit(@NotNull Command cmd) {
@Command.Define(names = "sub-command", description = "This is a sub-command.")
- public static class MySubCommand extends CommandTemplate {
+ public static class MySubCommand extends CommandTemplate.Default {
public MySubCommand() {}
@Argument.Define(argType = CounterArgumentType.class, description = "This is a counter", names = "c")
diff --git a/src/test/java/lanat/test/manualTests/ManualTests.java b/src/test/java/lanat/test/manualTests/ManualTests.java
index bf66bdc9..54516626 100644
--- a/src/test/java/lanat/test/manualTests/ManualTests.java
+++ b/src/test/java/lanat/test/manualTests/ManualTests.java
@@ -2,28 +2,26 @@
import lanat.ArgumentParser;
import lanat.CLInput;
-import lanat.Command;
import org.junit.jupiter.api.Test;
import java.io.ByteArrayInputStream;
+import java.util.Arrays;
public final class ManualTests {
@Test
public void main() {
- String input = "";
+ String input = " ";
// write some stuff to stdin
System.setIn(new ByteArrayInputStream("hello world\ngoodbye".getBytes()));
- var parsed = new ArgumentParser(CommandTemplateExample.class) {{
- this.addCommand(new Command(CommandTemplateExample.MySubCommand.class) {{
- this.addCommand(new Command(CommandTemplateExample.MySubCommand.AnotherSubCommand.class));
- }});
- }}
- .parse(CLInput.from(input))
- .printErrors()
- .printHelpIfNoInput()
- .into(CommandTemplateExample.class);
+ var parsed = ArgumentParser.parseFromInto(
+ CommandTemplateExample.class,
+ CLInput.from(input),
+ o -> o.exitIfErrors()
+ .printErrors()
+ .printHelpIfNoInput()
+ );
parsed.string
.ifPresentOrElse(
@@ -35,5 +33,6 @@ public void main() {
System.out.println(parsed.subCommand.counter);
System.out.println(parsed.subCommand.anotherSubCommand.counter);
System.out.println(parsed.stdin);
+ System.out.println(Arrays.toString(parsed.bytes));
}
}
\ No newline at end of file
diff --git a/src/test/java/lanat/test/units/TestArgumentTypes.java b/src/test/java/lanat/test/units/TestArgumentTypes.java
index 5846d49f..c04e4373 100644
--- a/src/test/java/lanat/test/units/TestArgumentTypes.java
+++ b/src/test/java/lanat/test/units/TestArgumentTypes.java
@@ -4,6 +4,7 @@
import lanat.argumentTypes.*;
import lanat.test.TestingParser;
import lanat.test.UnitTests;
+import lanat.utils.Range;
import org.junit.jupiter.api.Test;
import java.io.File;
@@ -24,8 +25,11 @@ protected TestingParser setParser() {
this.addArgument(Argument.create(new IntegerArgumentType(), "integer"));
this.addArgument(Argument.create(new FloatArgumentType(), "float"));
this.addArgument(Argument.create(new StringArgumentType(), "string"));
- this.addArgument(Argument.create(new MultipleStringsArgumentType(), "multiple-strings"));
- this.addArgument(Argument.create(new FileArgumentType(), "file"));
+ this.addArgument(Argument.create(new MultipleStringsArgumentType(Range.AT_LEAST_ONE), "multiple-strings"));
+ this.addArgument(Argument.create(new MultipleNumbersArgumentType<>(
+ Range.AT_LEAST_ONE, new Integer[] { 10101 }), "multiple-ints")
+ );
+ this.addArgument(Argument.create(new FileArgumentType(true), "file"));
this.addArgument(Argument.create(new EnumArgumentType<>(TestEnum.TWO), "enum"));
this.addArgument(Argument.create(new KeyValuesArgumentType<>(new IntegerArgumentType()), "key-value"));
this.addArgument(Argument.create(new NumberRangeArgumentType<>(3, 10), "int-range"));
@@ -75,10 +79,16 @@ public void testStrings() {
assertArrayEquals(new String[] { "hello world" }, this.parseArg("multiple-strings", "'hello world'"));
}
+ @Test
+ public void testNumbers() {
+ assertArrayEquals(new Integer[] { 4 }, this.parseArg("multiple-ints", "4"));
+ assertArrayEquals(new Integer[] { 4, 5, 6 }, this.parseArg("multiple-ints", "4 5 6"));
+ assertArrayEquals(new Integer[] { 10101 }, this.parseArg("multiple-ints", ""));
+ }
+
@Test
public void testFile() {
- assertEquals("hello.txt", this.parseArg("file", "hello.txt").getName());
- this.assertNotPresent("file");
+ assertNull(this.parseArg("file", "hello.txt"));
}
@Test
diff --git a/src/test/java/lanat/test/units/commandTemplates/CmdTemplates.java b/src/test/java/lanat/test/units/commandTemplates/CmdTemplates.java
index 8d8a9b50..aa4d2578 100644
--- a/src/test/java/lanat/test/units/commandTemplates/CmdTemplates.java
+++ b/src/test/java/lanat/test/units/commandTemplates/CmdTemplates.java
@@ -82,5 +82,8 @@ public static class CmdTemplate4 extends CommandTemplate {
@Argument.Define
public Double number2;
+
+ @Argument.Define
+ public Byte[] bytes;
}
}
diff --git a/src/test/java/lanat/test/units/commandTemplates/TestFromInto.java b/src/test/java/lanat/test/units/commandTemplates/TestFromInto.java
index e3dd43de..6458b9f6 100644
--- a/src/test/java/lanat/test/units/commandTemplates/TestFromInto.java
+++ b/src/test/java/lanat/test/units/commandTemplates/TestFromInto.java
@@ -3,10 +3,7 @@
import lanat.ArgumentParser;
import lanat.CLInput;
import lanat.CommandTemplate;
-import lanat.argumentTypes.BooleanArgumentType;
-import lanat.argumentTypes.DoubleArgumentType;
-import lanat.argumentTypes.IntegerArgumentType;
-import lanat.argumentTypes.StringArgumentType;
+import lanat.argumentTypes.*;
import lanat.exceptions.CommandTemplateException;
import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.DisplayName;
@@ -57,7 +54,6 @@ public void testNestedCommands() {
assertEquals(52, result.cmd2.cmd3.number);
}
-
@Test
@DisplayName("test type inference for fields argument types")
public void testTypeInference() {
@@ -67,5 +63,17 @@ public void testTypeInference() {
assertTrue(result.getArgument("text").argType instanceof StringArgumentType);
assertTrue(result.getArgument("flag").argType instanceof BooleanArgumentType);
assertTrue(result.getArgument("number2").argType instanceof DoubleArgumentType);
+ assertTrue(result.getArgument("bytes").argType instanceof MultipleNumbersArgumentType);
+ }
+
+ @Test
+ @DisplayName("test array parsed values are properly converted")
+ public void testArrayParsedValues() {
+ final var result = ArgumentParser.parseFromInto(
+ CmdTemplates.CmdTemplate4.class,
+ CLInput.from("--bytes 5 12 89")
+ );
+
+ assertArrayEquals(new Byte[] {5, 12, 89}, result.bytes);
}
}
\ No newline at end of file