Make use of the parser repository in the component builder

This commit is contained in:
Alexander Söderberg 2020-09-17 12:09:15 +02:00
parent 14b5d9fc3c
commit b3d75496b5
No known key found for this signature in database
GPG key ID: C0207FF7EA146678
4 changed files with 116 additions and 42 deletions

View file

@ -135,7 +135,8 @@ public class Command<C extends CommandSender, M extends CommandMeta> {
public static <C extends CommandSender, M extends CommandMeta> Builder<C, M> newBuilder(@Nonnull final String commandName,
@Nonnull final M commandMeta,
@Nonnull final String... aliases) {
return new Builder<>(commandMeta, null, Collections.singletonList(StaticComponent.required(commandName, aliases)),
return new Builder<>(null, commandMeta, null,
Collections.singletonList(StaticComponent.required(commandName, aliases)),
new CommandExecutionHandler.NullCommandExecutionHandler<>(), "");
}
@ -223,12 +224,15 @@ public class Command<C extends CommandSender, M extends CommandMeta> {
@Nonnull private final CommandExecutionHandler<C> commandExecutionHandler;
@Nullable private final Class<? extends C> senderType;
@Nonnull private final String commandPermission;
@Nullable private final CommandManager<C, M> commandManager;
private Builder(@Nonnull final M commandMeta,
private Builder(@Nullable final CommandManager<C, M> commandManager,
@Nonnull final M commandMeta,
@Nullable final Class<? extends C> senderType,
@Nonnull final List<CommandComponent<C, ?>> commandComponents,
@Nonnull final CommandExecutionHandler<C> commandExecutionHandler,
@Nonnull final String commandPermission) {
this.commandManager = commandManager;
this.senderType = senderType;
this.commandComponents = Objects.requireNonNull(commandComponents, "Components may not be null");
this.commandExecutionHandler = Objects.requireNonNull(commandExecutionHandler, "Execution handler may not be null");
@ -236,6 +240,20 @@ public class Command<C extends CommandSender, M extends CommandMeta> {
this.commandMeta = Objects.requireNonNull(commandMeta, "Meta may not be null");
}
/**
* Supply a command manager instance to the builder. This will be used when attempting to
* retrieve command component parsers, in the case that they're needed. This
* is optional
*
* @param commandManager Command manager
* @return New builder instance using the provided command manager
*/
@Nonnull
public Builder<C, M> manager(@Nullable final CommandManager<C, M> commandManager) {
return new Builder<>(commandManager, this.commandMeta, this.senderType, this.commandComponents,
this.commandExecutionHandler, this.commandPermission);
}
/**
* Add a new command component to the command
*
@ -247,8 +265,8 @@ public class Command<C extends CommandSender, M extends CommandMeta> {
public <T> Builder<C, M> component(@Nonnull final CommandComponent<C, T> component) {
final List<CommandComponent<C, ?>> commandComponents = new LinkedList<>(this.commandComponents);
commandComponents.add(component);
return new Builder<>(this.commandMeta, this.senderType, commandComponents, this.commandExecutionHandler,
this.commandPermission);
return new Builder<>(this.commandManager, this.commandMeta, this.senderType, commandComponents,
this.commandExecutionHandler, this.commandPermission);
}
/**
@ -265,6 +283,9 @@ public class Command<C extends CommandSender, M extends CommandMeta> {
@Nonnull final String name,
@Nonnull final Consumer<CommandComponent.Builder<C, T>> builderConsumer) {
final CommandComponent.Builder<C, T> builder = CommandComponent.ofType(clazz, name);
if (this.commandManager != null) {
builder.manager(this.commandManager);
}
builderConsumer.accept(builder);
return this.component(builder.build());
}
@ -277,8 +298,8 @@ public class Command<C extends CommandSender, M extends CommandMeta> {
*/
@Nonnull
public Builder<C, M> handler(@Nonnull final CommandExecutionHandler<C> commandExecutionHandler) {
return new Builder<>(this.commandMeta, this.senderType, this.commandComponents, commandExecutionHandler,
this.commandPermission);
return new Builder<>(this.commandManager, this.commandMeta, this.senderType, this.commandComponents,
commandExecutionHandler, this.commandPermission);
}
/**
@ -289,8 +310,8 @@ public class Command<C extends CommandSender, M extends CommandMeta> {
*/
@Nonnull
public Builder<C, M> withSenderType(@Nonnull final Class<? extends C> senderType) {
return new Builder<>(this.commandMeta, senderType, this.commandComponents, this.commandExecutionHandler,
this.commandPermission);
return new Builder<>(this.commandManager, this.commandMeta, senderType, this.commandComponents,
this.commandExecutionHandler, this.commandPermission);
}
/**
@ -301,8 +322,8 @@ public class Command<C extends CommandSender, M extends CommandMeta> {
*/
@Nonnull
public Builder<C, M> withPermission(@Nonnull final String permission) {
return new Builder<>(this.commandMeta, this.senderType, this.commandComponents, this.commandExecutionHandler,
permission);
return new Builder<>(this.commandManager, this.commandMeta, this.senderType, this.commandComponents,
this.commandExecutionHandler, permission);
}
/**
@ -312,8 +333,8 @@ public class Command<C extends CommandSender, M extends CommandMeta> {
*/
@Nonnull
public Command<C, M> build() {
return new Command<>(Collections.unmodifiableList(this.commandComponents), this.commandExecutionHandler,
this.senderType, this.commandPermission, this.commandMeta);
return new Command<>(Collections.unmodifiableList(this.commandComponents),
this.commandExecutionHandler, this.senderType, this.commandPermission, this.commandMeta);
}
}

View file

@ -24,6 +24,7 @@
package com.intellectualsites.commands;
import com.google.common.reflect.TypeToken;
import com.intellectualsites.commands.components.CommandComponent;
import com.intellectualsites.commands.components.CommandSyntaxFormatter;
import com.intellectualsites.commands.components.StandardCommandSyntaxFormatter;
import com.intellectualsites.commands.components.parser.ParserRegistry;
@ -231,7 +232,20 @@ public abstract class CommandManager<C extends CommandSender, M extends CommandM
*/
@Nonnull
public Command.Builder<C, M> commandBuilder(@Nonnull final String name) {
return Command.newBuilder(name, this.createDefaultCommandMeta());
return Command.<C, M>newBuilder(name, this.createDefaultCommandMeta()).manager(this);
}
/**
* Create a new command component builder
*
* @param type Component type
* @param name Component name
* @param <T> Generic component name
* @return Component builder
*/
@Nonnull
public <T> CommandComponent.Builder<C, T> componentBuilder(@Nonnull final Class<T> type, @Nonnull final String name) {
return CommandComponent.<C, T>ofType(type, name).manager(this);
}
/**

View file

@ -23,9 +23,12 @@
//
package com.intellectualsites.commands.components;
import com.google.common.reflect.TypeToken;
import com.intellectualsites.commands.Command;
import com.intellectualsites.commands.CommandManager;
import com.intellectualsites.commands.components.parser.ComponentParseResult;
import com.intellectualsites.commands.components.parser.ComponentParser;
import com.intellectualsites.commands.components.parser.ParserParameters;
import com.intellectualsites.commands.sender.CommandSender;
import javax.annotation.Nonnull;
@ -263,9 +266,9 @@ public class CommandComponent<C extends CommandSender, T> implements Comparable<
private final Class<T> valueType;
private final String name;
private CommandManager<C, ?> manager;
private boolean required = true;
private ComponentParser<C, T> parser = (c, i) -> ComponentParseResult.failure(
new UnsupportedOperationException("No parser was specified"));
private ComponentParser<C, T> parser;
private String defaultValue = "";
protected Builder(@Nonnull final Class<T> valueType,
@ -274,6 +277,19 @@ public class CommandComponent<C extends CommandSender, T> implements Comparable<
this.name = name;
}
/**
* Set the command manager. Will be used to create a default parser
* if none was provided
*
* @param manager Command manager
* @return Builder instance
*/
@Nonnull
public Builder<C, T> manager(@Nonnull final CommandManager<C, ?> manager) {
this.manager = manager;
return this;
}
/**
* Indicates that the component is required.
* All components prior to any other required
@ -340,6 +356,14 @@ public class CommandComponent<C extends CommandSender, T> implements Comparable<
*/
@Nonnull
public CommandComponent<C, T> build() {
if (this.parser == null && this.manager != null) {
this.parser = this.manager.getParserRegistry().createParser(TypeToken.of(valueType), ParserParameters.empty())
.orElse(null);
}
if (this.parser == null) {
this.parser = (c, i) -> ComponentParseResult
.failure(new UnsupportedOperationException("No parser was specified"));
}
return new CommandComponent<>(this.required, this.name, this.parser, this.defaultValue, this.valueType);
}

View file

@ -42,66 +42,81 @@ import java.util.concurrent.CompletionException;
class CommandTreeTest {
private static final int EXPECTED_INPUT_NUMBER = 15;
private static CommandManager<CommandSender, SimpleCommandMeta> commandManager;
private static CommandManager<CommandSender, SimpleCommandMeta> manager;
@BeforeAll
static void newTree() {
commandManager = new TestCommandManager();
commandManager.command(commandManager.commandBuilder("test", SimpleCommandMeta.empty())
.component(StaticComponent.required("one")).build())
.command(commandManager.commandBuilder("test", SimpleCommandMeta.empty())
.component(StaticComponent.required("two")).withPermission("no").build())
.command(commandManager.commandBuilder("test", Collections.singleton("other"),
SimpleCommandMeta.empty())
.component(StaticComponent.required("opt", "öpt"))
.component(IntegerComponent
manager = new TestCommandManager();
manager.command(manager.commandBuilder("test", SimpleCommandMeta.empty())
.component(StaticComponent.required("one")).build())
.command(manager.commandBuilder("test", SimpleCommandMeta.empty())
.component(StaticComponent.required("two")).withPermission("no").build())
.command(manager.commandBuilder("test", Collections.singleton("other"),
SimpleCommandMeta.empty())
.component(StaticComponent.required("opt", "öpt"))
.component(IntegerComponent
.optional("num", EXPECTED_INPUT_NUMBER))
.build())
.command(commandManager.commandBuilder("req").withSenderType(SpecificCommandSender.class).build());
.build())
.command(manager.commandBuilder("req").withSenderType(SpecificCommandSender.class).build());
}
@Test
void parse() {
final Optional<Command<CommandSender, SimpleCommandMeta>> command = commandManager.getCommandTree()
.parse(new CommandContext<>(
final Optional<Command<CommandSender, SimpleCommandMeta>> command = manager.getCommandTree()
.parse(new CommandContext<>(
new TestCommandSender()),
new LinkedList<>(
Arrays.asList("test",
"one")));
Assertions.assertTrue(command.isPresent());
Assertions.assertThrows(NoPermissionException.class, () -> commandManager.getCommandTree()
.parse(new CommandContext<>(
Assertions.assertThrows(NoPermissionException.class, () -> manager.getCommandTree()
.parse(new CommandContext<>(
new TestCommandSender()),
new LinkedList<>(
Arrays.asList("test", "two"))));
commandManager.getCommandTree()
.parse(new CommandContext<>(new TestCommandSender()), new LinkedList<>(Arrays.asList("test", "opt")))
.ifPresent(c -> c.getCommandExecutionHandler().execute(new CommandContext<>(new TestCommandSender())));
commandManager.getCommandTree()
.parse(new CommandContext<>(new TestCommandSender()), new LinkedList<>(Arrays.asList("test", "opt", "12")))
.ifPresent(c -> c.getCommandExecutionHandler().execute(new CommandContext<>(new TestCommandSender())));
manager.getCommandTree()
.parse(new CommandContext<>(new TestCommandSender()), new LinkedList<>(Arrays.asList("test", "opt")))
.ifPresent(c -> c.getCommandExecutionHandler().execute(new CommandContext<>(new TestCommandSender())));
manager.getCommandTree()
.parse(new CommandContext<>(new TestCommandSender()), new LinkedList<>(Arrays.asList("test", "opt", "12")))
.ifPresent(c -> c.getCommandExecutionHandler().execute(new CommandContext<>(new TestCommandSender())));
}
@Test
void testAlias() {
commandManager.getCommandTree()
.parse(new CommandContext<>(new TestCommandSender()), new LinkedList<>(Arrays.asList("other", "öpt", "12")))
.ifPresent(c -> c.getCommandExecutionHandler().execute(new CommandContext<>(new TestCommandSender())));
manager.getCommandTree()
.parse(new CommandContext<>(new TestCommandSender()), new LinkedList<>(Arrays.asList("other", "öpt", "12")))
.ifPresent(c -> c.getCommandExecutionHandler().execute(new CommandContext<>(new TestCommandSender())));
}
@Test
void getSuggestions() {
Assertions.assertFalse(
commandManager.getCommandTree().getSuggestions(new CommandContext<>(new TestCommandSender()), new LinkedList<>(
manager.getCommandTree().getSuggestions(new CommandContext<>(new TestCommandSender()), new LinkedList<>(
Collections.singletonList("test "))).isEmpty());
}
@Test
void testRequiredSender() {
Assertions.assertThrows(CompletionException.class, () ->
commandManager.executeCommand(new TestCommandSender(), "req").join());
manager.executeCommand(new TestCommandSender(), "req").join());
}
@Test
void testDefaultParser() {
manager.command(
manager.commandBuilder("default")
.component(manager.componentBuilder(Integer.class, "int").build())
.handler(context -> {
final int number = context.getRequired("int");
System.out.printf("Supplied number is: %d\n", number);
})
.build()
);
manager.executeCommand(new TestCommandSender(), "default 5").join();
}
public static final class SpecificCommandSender extends TestCommandSender {
}