Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add built-in placeholders for comparing values #11

Merged
merged 3 commits into from
Mar 31, 2024
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
27 changes: 27 additions & 0 deletions core/src/main/java/io/github/almightysatan/slams/Placeholder.java
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,28 @@ public interface Placeholder extends PlaceholderResolver {
});
}

/**
* Returns a new {@link Placeholder}. This placeholder compares its first two arguments using the given function. If
* the function evaluates to {@code true}, this placeholder will return the third argument as its value, otherwise
* the fourth argument is returned.
* Example format: {@code <if_eq:<time>:1:1 second:<time> seconds>}
*
* @param key the placeholder's key
* @param comparisonFunction a function that compares the first two arguments of this placeholder
* @return a new placeholder
*/
static @NotNull Placeholder comparison(@NotNull String key, @NotNull ComparisonFunction comparisonFunction) {
Objects.requireNonNull(comparisonFunction);
return of(key, (context, arguments) -> {
if (arguments.size() < 2)
return "INVALID_COMPARISON";
if (comparisonFunction.value(arguments.get(0), arguments.get(1)))
return arguments.size() > 2 ? arguments.get(2) : "";
else
return arguments.size() > 3 ? arguments.get(3) : "";
});
}

@FunctionalInterface
interface ValueFunction {
@NotNull String value(@Nullable Context context, @NotNull List<@NotNull String> arguments);
Expand Down Expand Up @@ -349,4 +371,9 @@ interface ArgumentIndependentContextualValueFunction<T extends Context> extends
return this.value(context);
}
}

@FunctionalInterface
interface ComparisonFunction {
boolean value(@NotNull String argument0, @NotNull String argument1);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.math.BigDecimal;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.BooleanSupplier;
import java.util.function.Predicate;

Expand Down Expand Up @@ -110,6 +112,25 @@ public interface PlaceholderResolver {
return of(placeholderResolvers.toArray(new PlaceholderResolver[0]));
}

/**
* Returns a {@link PlaceholderResolver} containing some built-in placeholders, including, but no limited to
* <ul>
* <li>if_eq</li>
* <li>if_neq</li>
* <li>if_num_eq</li>
* <li>if_num_neq</li>
* <li>if_num_lt</li>
* <li>if_num_gt</li>
* <li>if_num_le</li>
* <li>if_num_ge</li>
* </ul>
*
* @return a new {@link PlaceholderResolver}
*/
static @NotNull PlaceholderResolver builtInPlaceholders() {
return builder().builtIn().build();
}

/**
* Returns a new {@link Builder Builder}.
*
Expand Down Expand Up @@ -384,5 +405,42 @@ interface Builder {
default @NotNull Builder conditional(@NotNull String key, @NotNull BooleanSupplier supplier) {
return this.add(Placeholder.conditional(key, supplier));
}

/**
* Adds built-in placeholders, including, but no limited to
* <ul>
* <li>if_eq</li>
* <li>if_neq</li>
* <li>if_num_eq</li>
* <li>if_num_neq</li>
* <li>if_num_lt</li>
* <li>if_num_gt</li>
* <li>if_num_le</li>
* <li>if_num_ge</li>
* </ul>
*
* @return this {@link Builder}
*/
default @NotNull Builder builtIn() {
BiFunction<String, BiFunction<BigDecimal, BigDecimal, Boolean>, Placeholder> numberComparison = (key, fun) ->
Placeholder.comparison(key, (arg0, arg1) -> {
try {
return fun.apply(new BigDecimal(arg0), new BigDecimal(arg1));
} catch (NumberFormatException e) {
return false;
}
});

this.add(Placeholder.comparison("if_eq", String::equals));
this.add(Placeholder.comparison("if_neq", (arg0, arg1) -> !arg0.equals(arg1)));

this.add(numberComparison.apply("if_num_eq", (arg0, arg1) -> arg0.compareTo(arg1) == 0));
this.add(numberComparison.apply("if_num_neq", (arg0, arg1) -> arg0.compareTo(arg1) != 0));
this.add(numberComparison.apply("if_num_lt", (arg0, arg1) -> arg0.compareTo(arg1) < 0));
this.add(numberComparison.apply("if_num_gt", (arg0, arg1) -> arg0.compareTo(arg1) > 0));
this.add(numberComparison.apply("if_num_le", (arg0, arg1) -> arg0.compareTo(arg1) <= 0));
this.add(numberComparison.apply("if_num_ge", (arg0, arg1) -> arg0.compareTo(arg1) >= 0));
return this;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,9 @@ public boolean has(@NotNull String name) {
}

/**
* Creates a new {@link ContextTagResolver} from the given {@link PlaceholderResolver}. Any string returned by
* placeholders will be deserialized.
* Creates a new {@link ContextTagResolver} from the given {@link PlaceholderResolver}. All tags returned by this
* {@link ContextTagResolver} will be pre-process tags and their value will therefore be parsed by MiniMessage. Do
* not use this method for placeholders that return user input!
*
* @param placeholderResolver the {@link PlaceholderResolver}
* @return a new {@link ContextTagResolver}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class ContextTagResolverImpl {
if (placeholder == null)
return null;
String value = placeholder.value(context, this.argumentQueueToList(arguments));
return Tag.selfClosingInserting(eval ? ctx.deserialize(value) : Component.text(value));
return eval ? Tag.preProcessParsed(value) : Tag.selfClosingInserting(Component.text(value));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ public void testConditionalPlaceholder() throws IOException {
}

@Test
public void testConditionalContextTagResolver() throws IOException {
public void testConditionalUnsafePlaceholder() throws IOException {
Slams langManager = Slams.create("0");
AdventureMessage entry = AdventureMessage.of("test", langManager, ContextTagResolver.of(
ContextTagResolver.ofUnsafe(Placeholder.conditional("ifn", () -> false)),
Expand All @@ -144,6 +144,19 @@ public void testConditionalContextTagResolver() throws IOException {
assertEquals("Hello <def>", component.content());
}

@Test
public void testComparisonPlaceholder() throws IOException {
Slams langManager = Slams.create("0");
AdventureMessage entry = AdventureMessage.of("test", langManager, ContextTagResolver.ofUnsafe(
PlaceholderResolver.builder().builtIn().constant("abc", "World").constant("number", "150").build()
));

langManager.load("0", values -> values.put("test", "Hello <if_num_eq:'<number>':150:'<abc>':Earth>"));

TextComponent component = (TextComponent) entry.value();
assertEquals("Hello World", component.content());
}

@Test
public void testArray() throws IOException {
Slams langManager = Slams.create("0");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,13 +96,14 @@ public void testBasicCurlyParentheses() {

@Test
public void testPlaceholders() {
PlaceholderResolver placeholderResolver = PlaceholderResolver.of(
Placeholder.constant("abc", "def"),
Placeholder.constant("a<b", "c"),
Placeholder.constant("a>b", "d"),
Placeholder.withArgs("arg", args -> args.get(0)),
Placeholder.conditional("if", () -> true),
Placeholder.conditional("ifn", () -> false));
PlaceholderResolver placeholderResolver = PlaceholderResolver.builder()
.constant("abc", "def")
.constant("a<b", "c")
.constant("a>b", "d")
.withArgs("arg", args -> args.get(0))
.conditional("if", () -> true)
.conditional("ifn", () -> false)
.builtIn().build();
Function<String, String> eval = input -> new CompositeComponent(PlaceholderStyle.ANGLE_BRACKETS, input, PlaceholderResolver.empty()).value(null, placeholderResolver);

Assertions.assertEquals("", eval.apply(""));
Expand Down Expand Up @@ -142,6 +143,11 @@ public void testPlaceholders() {
Assertions.assertEquals("Hello World", eval.apply("Hello <if:World:Earth>"));
Assertions.assertEquals("Hello Earth", eval.apply("Hello <ifn:World:Earth>"));
Assertions.assertEquals("Hello def", eval.apply("Hello <if:<abc>:fail>"));

// built-in
Assertions.assertEquals("Hello World", eval.apply("Hello <if_eq:abc:abc:World:Earth>"));
Assertions.assertEquals("Hello World", eval.apply("Hello <if_num_eq:150:150:World:Earth>"));
Assertions.assertEquals("Hello Earth", eval.apply("Hello <if_num_eq:100:150:World:Earth>"));
}

@Test
Expand Down
Loading