Skip to content

Commit

Permalink
GH-257 Add argument resolvers for temportal amounts, temporal accesso…
Browse files Browse the repository at this point in the history
…rs (#256)

* Add an argument resolver for temporal amounts

* Add an argument resolver for temporal accessors

* Fix code style issues
  • Loading branch information
rchomczyk authored Oct 20, 2023
1 parent 8dd5682 commit f2dc624
Show file tree
Hide file tree
Showing 6 changed files with 191 additions and 96 deletions.
Original file line number Diff line number Diff line change
@@ -1,19 +1,11 @@
package dev.rollczi.litecommands.argument.resolver.standard;

import dev.rollczi.litecommands.argument.Argument;
import dev.rollczi.litecommands.argument.resolver.ArgumentResolver;
import dev.rollczi.litecommands.argument.parser.ParseResult;
import dev.rollczi.litecommands.invalidusage.InvalidUsage;
import dev.rollczi.litecommands.invocation.Invocation;
import dev.rollczi.litecommands.suggestion.SuggestionContext;
import dev.rollczi.litecommands.suggestion.SuggestionResult;
import dev.rollczi.litecommands.time.DurationParser;

import java.time.Duration;
import java.util.Arrays;
import java.util.List;

public class DurationArgumentResolver<SENDER> extends ArgumentResolver<SENDER, Duration> {
public class DurationArgumentResolver<SENDER> extends TemporalAmountArgumentResolver<SENDER, Duration> {

private static final List<String> SUGGESTIONS_LIST = Arrays.asList(
"1s", "5s", "10s", "30s",
Expand All @@ -22,21 +14,7 @@ public class DurationArgumentResolver<SENDER> extends ArgumentResolver<SENDER, D
"1d", "7d", "30d"
);


@Override
protected ParseResult<Duration> parse(Invocation<SENDER> invocation, Argument<Duration> context, String argument) {
try {
Duration parse = DurationParser.DATE_TIME_UNITS.parse(argument);

return ParseResult.success(parse);
}
catch (IllegalArgumentException e) {
return ParseResult.failure(InvalidUsage.Cause.INVALID_ARGUMENT);
}
}

@Override
public SuggestionResult suggest(Invocation<SENDER> invocation, Argument<Duration> argument, SuggestionContext context) {
return SuggestionResult.of(SUGGESTIONS_LIST);
public DurationArgumentResolver() {
super(DurationParser.DATE_TIME_UNITS, () -> SUGGESTIONS_LIST);
}
}
Original file line number Diff line number Diff line change
@@ -1,61 +1,27 @@
package dev.rollczi.litecommands.argument.resolver.standard;

import dev.rollczi.litecommands.argument.Argument;
import dev.rollczi.litecommands.argument.parser.ParseResult;
import dev.rollczi.litecommands.argument.resolver.MultipleArgumentResolver;
import dev.rollczi.litecommands.input.raw.RawCommand;
import dev.rollczi.litecommands.input.raw.RawInput;
import dev.rollczi.litecommands.invocation.Invocation;
import dev.rollczi.litecommands.message.LiteMessages;
import static dev.rollczi.litecommands.argument.resolver.standard.TemporalAccessorUtils.allDaysOfWeek;
import static dev.rollczi.litecommands.message.LiteMessages.INSTANT_INVALID_FORMAT;
import static java.time.ZoneOffset.UTC;

import dev.rollczi.litecommands.message.MessageRegistry;
import dev.rollczi.litecommands.range.Range;
import dev.rollczi.litecommands.suggestion.SuggestionContext;
import dev.rollczi.litecommands.suggestion.SuggestionResult;

import java.time.DateTimeException;
import java.time.Instant;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.stream.IntStream;

@SuppressWarnings("Convert2MethodRef")
public class InstantArgumentResolver<SENDER> implements MultipleArgumentResolver<SENDER, Instant> {
public class InstantArgumentResolver<SENDER> extends TemporalAccessorArgumentResolver<SENDER, Instant> {

private final DateTimeFormatter formatter = DateTimeFormatter
private static final DateTimeFormatter FORMATTER = DateTimeFormatter
.ofPattern("yyyy-MM-dd HH:mm:ss")
.withZone(ZoneOffset.UTC);

private final MessageRegistry<SENDER> messageRegistry;
.withZone(UTC);

public InstantArgumentResolver(MessageRegistry<SENDER> messageRegistry) {
this.messageRegistry = messageRegistry;
}

@Override
public ParseResult<Instant> parse(Invocation<SENDER> invocation, Argument<Instant> argument, RawInput rawInput) {
String commandInput = String.join(RawCommand.COMMAND_SEPARATOR, rawInput.seeNext(2));

try {
String rawInstant = String.join(" ", rawInput.next(2));
return ParseResult.success(Instant.from(formatter.parse(rawInstant)));
}
catch (DateTimeException ignored) {
return ParseResult.failure(this.messageRegistry.getInvoked(LiteMessages.INSTANT_INVALID_FORMAT, invocation, commandInput));
}
super(
messageRegistry,
INSTANT_INVALID_FORMAT,
FORMATTER,
Instant::from,
() -> allDaysOfWeek(Instant.now())
);
}

@Override
public SuggestionResult suggest(Invocation<SENDER> invocation, Argument<Instant> argument, SuggestionContext context) {
return IntStream.range(0, 7)
.mapToObj(day -> Instant.now().plus(day, ChronoUnit.DAYS))
.map(instant -> formatter.format(instant))
.collect(SuggestionResult.collector());
}

@Override
public Range getRange(Argument<Instant> instantArgument) {
return Range.of(2);
}

}
Original file line number Diff line number Diff line change
@@ -1,39 +1,19 @@
package dev.rollczi.litecommands.argument.resolver.standard;

import dev.rollczi.litecommands.argument.Argument;
import dev.rollczi.litecommands.argument.resolver.ArgumentResolver;
import dev.rollczi.litecommands.argument.parser.ParseResult;
import dev.rollczi.litecommands.invalidusage.InvalidUsage;
import dev.rollczi.litecommands.invocation.Invocation;
import dev.rollczi.litecommands.suggestion.SuggestionContext;
import dev.rollczi.litecommands.suggestion.SuggestionResult;
import dev.rollczi.litecommands.time.PeriodParser;

import java.time.Period;
import java.util.Arrays;
import java.util.List;

public class PeriodArgumentResolver<SENDER> extends ArgumentResolver<SENDER, Period> {
public class PeriodArgumentResolver<SENDER> extends TemporalAmountArgumentResolver<SENDER, Period> {

private static final List<String> SUGGESTIONS_LIST = Arrays.asList(
"1h", "3h", "7h",
"1d", "7d", "30d",
"1m", "3m", "6m", "1y", "5y"
);

@Override
protected ParseResult<Period> parse(Invocation<SENDER> invocation, Argument<Period> context, String argument) {
try {
Period parse = PeriodParser.DATE_UNITS.parse(argument);

return ParseResult.success(parse);
} catch (IllegalArgumentException e) {
return ParseResult.failure(InvalidUsage.Cause.INVALID_ARGUMENT);
}
}

@Override
public SuggestionResult suggest(Invocation<SENDER> invocation, Argument<Period> argument, SuggestionContext context) {
return SuggestionResult.of(SUGGESTIONS_LIST);
public PeriodArgumentResolver() {
super(PeriodParser.DATE_UNITS, () -> SUGGESTIONS_LIST);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package dev.rollczi.litecommands.argument.resolver.standard;

import static dev.rollczi.litecommands.argument.parser.ParseResult.failure;
import static dev.rollczi.litecommands.argument.parser.ParseResult.success;
import static dev.rollczi.litecommands.input.raw.RawCommand.COMMAND_SEPARATOR;

import dev.rollczi.litecommands.argument.Argument;
import dev.rollczi.litecommands.argument.parser.ParseResult;
import dev.rollczi.litecommands.argument.resolver.MultipleArgumentResolver;
import dev.rollczi.litecommands.input.raw.RawInput;
import dev.rollczi.litecommands.invocation.Invocation;
import dev.rollczi.litecommands.message.MessageKey;
import dev.rollczi.litecommands.message.MessageRegistry;
import dev.rollczi.litecommands.range.Range;
import dev.rollczi.litecommands.suggestion.SuggestionContext;
import dev.rollczi.litecommands.suggestion.SuggestionResult;
import java.time.DateTimeException;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalQuery;
import java.util.List;
import java.util.function.Supplier;

class TemporalAccessorArgumentResolver<SENDER, UNIT extends TemporalAccessor> implements MultipleArgumentResolver<SENDER, UNIT> {

private static final String ARGUMENT_SEPARATOR = " ";
private static final String FORMATTER_ELEMENT_SEPARATOR = " ";
private final MessageRegistry<SENDER> messageRegistry;
private final MessageKey<String> invalidFormatMessage;
private final DateTimeFormatter formatter;
private final TemporalQuery<UNIT> query;
private final Supplier<List<UNIT>> suggestions;
private final int argumentCount;

protected TemporalAccessorArgumentResolver(
MessageRegistry<SENDER> messageRegistry,
MessageKey<String> invalidFormatMessage,
DateTimeFormatter formatter,
TemporalQuery<UNIT> query,
Supplier<List<UNIT>> suggestions
) {
this.messageRegistry = messageRegistry;
this.invalidFormatMessage = invalidFormatMessage;
this.formatter = formatter;
this.query = query;
this.suggestions = suggestions;
this.argumentCount = getElementCount(formatter);
}

protected TemporalAccessorArgumentResolver(
MessageRegistry<SENDER> messageRegistry,
MessageKey<String> invalidFormatMessage,
String formatterPattern,
TemporalQuery<UNIT> query,
Supplier<List<UNIT>> suggestions
) {
this(messageRegistry, invalidFormatMessage, DateTimeFormatter.ofPattern(formatterPattern), query, suggestions);
}

@Override
public ParseResult<UNIT> parse(Invocation<SENDER> invocation, Argument<UNIT> argument, RawInput rawInput) {
String commandInput = String.join(COMMAND_SEPARATOR, rawInput.seeNext(this.argumentCount));
try {
String rawInstant = String.join(ARGUMENT_SEPARATOR, rawInput.next(this.argumentCount));
return success(this.formatter.parse(rawInstant, query));
} catch (DateTimeException exception) {
return failure(this.messageRegistry.getInvoked(this.invalidFormatMessage, invocation, commandInput));
}
}

@Override
public SuggestionResult suggest(Invocation<SENDER> invocation, Argument<UNIT> argument, SuggestionContext context) {
return this.suggestions.get().stream()
.map(this.formatter::format)
.collect(SuggestionResult.collector());
}

@Override
public Range getRange(Argument<UNIT> unitArgument) {
return Range.of(this.argumentCount);
}

private int getElementCount(DateTimeFormatter formatter) {
return formatter.toString().split(FORMATTER_ELEMENT_SEPARATOR).length;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package dev.rollczi.litecommands.argument.resolver.standard;

import static java.time.temporal.ChronoUnit.DAYS;
import static java.time.temporal.ChronoUnit.HOURS;
import static java.time.temporal.ChronoUnit.YEARS;

import java.time.temporal.ChronoUnit;
import java.time.temporal.Temporal;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

final class TemporalAccessorUtils {

private static final int WEEK_DAYS = 7;
private static final int HOURS_IN_DAY = 24;
private static final int YEARS_IN_DECADE = 10;

private TemporalAccessorUtils() {

}

static <T extends Temporal> List<T> allDaysOfWeek(T start) {
return generateTemporal(start, DAYS, WEEK_DAYS);
}

static <T extends Temporal> List<T> allHoursOfDay(T start) {
return generateTemporal(start, HOURS, HOURS_IN_DAY);
}

static <T extends Temporal> List<T> allYearsOfDecade(T start) {
return generateTemporal(start, YEARS, YEARS_IN_DECADE);
}

@SuppressWarnings("unchecked")
private static <T extends Temporal> List<T> generateTemporal(T start, ChronoUnit unit, int countGenerate) {
Class<T> temporalClass = (Class<T>) start.getClass();
return IntStream.range(0, countGenerate).boxed()
.map(temporalCount -> start.plus(temporalCount, unit))
.filter(temporalClass::isInstance)
.map(temporalClass::cast)
.collect(Collectors.toList());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package dev.rollczi.litecommands.argument.resolver.standard;

import static dev.rollczi.litecommands.argument.parser.ParseResult.failure;
import static dev.rollczi.litecommands.argument.parser.ParseResult.success;
import static dev.rollczi.litecommands.invalidusage.InvalidUsage.Cause.INVALID_ARGUMENT;

import dev.rollczi.litecommands.argument.Argument;
import dev.rollczi.litecommands.argument.parser.ParseResult;
import dev.rollczi.litecommands.argument.resolver.ArgumentResolver;
import dev.rollczi.litecommands.invocation.Invocation;
import dev.rollczi.litecommands.suggestion.SuggestionContext;
import dev.rollczi.litecommands.suggestion.SuggestionResult;
import dev.rollczi.litecommands.time.TemporalAmountParser;
import java.time.temporal.TemporalAmount;
import java.util.List;
import java.util.function.Supplier;

class TemporalAmountArgumentResolver<SENDER, UNIT extends TemporalAmount> extends ArgumentResolver<SENDER, UNIT> {

private final TemporalAmountParser<UNIT> parser;
private final Supplier<List<String>> suggestions;

protected TemporalAmountArgumentResolver(TemporalAmountParser<UNIT> parser, Supplier<List<String>> suggestions) {
this.parser = parser;
this.suggestions = suggestions;
}

@Override
protected ParseResult<UNIT> parse(Invocation<SENDER> invocation, Argument<UNIT> context, String argument) {
try {
return success(parser.parse(argument));
} catch (IllegalArgumentException exception) {
return failure(INVALID_ARGUMENT);
}
}

@Override
public SuggestionResult suggest(Invocation<SENDER> invocation, Argument<UNIT> argument, SuggestionContext context) {
return SuggestionResult.of(suggestions.get());
}
}

0 comments on commit f2dc624

Please sign in to comment.