mirror of
https://github.com/CarmJos/EasyConfiguration.git
synced 2026-06-04 18:48:20 +08:00
feat(text): Implement the ConfiguredText for simply text/msg functions.
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>cc.carm.lib</groupId>
|
||||
<artifactId>easyconfiguration-parent</artifactId>
|
||||
<version>4.0.0</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<properties>
|
||||
<maven.compiler.source>${project.jdk.version}</maven.compiler.source>
|
||||
<maven.compiler.target>${project.jdk.version}</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
||||
</properties>
|
||||
|
||||
<artifactId>easyconfiguration-feature-text</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>easyconfiguration-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>easyconfiguration-yaml</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,173 @@
|
||||
package cc.carm.lib.configuration.value.text;
|
||||
|
||||
import cc.carm.lib.configuration.adapter.ValueAdapter;
|
||||
import cc.carm.lib.configuration.adapter.ValueType;
|
||||
import cc.carm.lib.configuration.builder.AbstractConfigBuilder;
|
||||
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
||||
import cc.carm.lib.configuration.value.ValueManifest;
|
||||
import cc.carm.lib.configuration.value.standard.ConfiguredValue;
|
||||
import cc.carm.lib.configuration.value.text.data.TextContents;
|
||||
import cc.carm.lib.configuration.value.text.function.TextDispatcher;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* @param <MSG> The type of the message
|
||||
* @param <RECEIVER> The type of the receiver
|
||||
*/
|
||||
public class ConfiguredText<MSG, RECEIVER> extends ConfiguredValue<TextContents> {
|
||||
|
||||
public static <M, R> Builder<M, R, ?> builder() {
|
||||
return new StardardBuilder<>();
|
||||
}
|
||||
|
||||
public static final ValueType<TextContents> TEXT_TYPE = ValueType.of(TextContents.class);
|
||||
public static final ValueAdapter<TextContents> TEXT_ADAPTER = new ValueAdapter<>(TEXT_TYPE,
|
||||
(h, t, d) -> d.serialize(),
|
||||
(h, t, d) -> TextContents.deserialize(d)
|
||||
);
|
||||
|
||||
protected final @NotNull BiFunction<RECEIVER, String, String> parser;
|
||||
protected final @NotNull BiFunction<RECEIVER, String, MSG> compiler;
|
||||
protected final @NotNull BiConsumer<RECEIVER, List<MSG>> dispatcher;
|
||||
|
||||
protected final @NotNull String[] params; // The parameters of the message.
|
||||
|
||||
public ConfiguredText(@NotNull ValueManifest<TextContents> manifest,
|
||||
@NotNull BiFunction<RECEIVER, String, String> parser,
|
||||
@NotNull BiFunction<RECEIVER, String, MSG> compiler,
|
||||
@NotNull BiConsumer<RECEIVER, List<MSG>> dispatcher,
|
||||
@NotNull String[] params) {
|
||||
super(manifest, TEXT_ADAPTER);
|
||||
this.parser = parser;
|
||||
this.compiler = compiler;
|
||||
this.dispatcher = dispatcher;
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
public TextDispatcher<MSG, RECEIVER, ?> prepare(@NotNull Object... values) {
|
||||
return new PreparedText<MSG, RECEIVER>(resolve(), this.params)
|
||||
.parser(this.parser).compiler(this.compiler)
|
||||
.dispatcher(this.dispatcher).placeholders(values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile the message for the receiver.
|
||||
*
|
||||
* @param receiver The receiver of the message.
|
||||
* @param values The values to replace the placeholders.
|
||||
* @return The compiled message.
|
||||
*/
|
||||
public List<MSG> compile(@NotNull RECEIVER receiver, @NotNull Object... values) {
|
||||
return prepare(values).compile(receiver);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile the message for the receiver and send it.
|
||||
*
|
||||
* @param receiver The receiver of the message.
|
||||
* @param values The values to replace the placeholders.
|
||||
* @return The compiled message.
|
||||
*/
|
||||
public MSG compileLine(@NotNull RECEIVER receiver, @NotNull Object... values) {
|
||||
return prepare(values).compileLine(receiver);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the message to the receiver.
|
||||
*
|
||||
* @param receiver The receiver of the message.
|
||||
* @param values The values to replace the placeholders.
|
||||
*/
|
||||
public void sendTo(@NotNull RECEIVER receiver, @NotNull Object... values) {
|
||||
prepare(values).to(receiver);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the message to the multiple receivers.
|
||||
*
|
||||
* @param receivers The receivers of the message.
|
||||
* @param values The values to replace the placeholders.
|
||||
*/
|
||||
public void sendToAll(@NotNull Iterable<? extends RECEIVER> receivers, @NotNull Object... values) {
|
||||
prepare(values).to(receivers);
|
||||
}
|
||||
|
||||
public abstract static class Builder<MSG, RECEIVER, SELF extends Builder<MSG, RECEIVER, SELF>>
|
||||
extends AbstractConfigBuilder<TextContents, ConfiguredText<MSG, RECEIVER>, ConfigurationHolder<?>, SELF> {
|
||||
protected @NotNull TextContents.Builder defaultBuilder = TextContents.builder();
|
||||
protected @NotNull String[] params = new String[0];
|
||||
|
||||
protected @NotNull BiFunction<RECEIVER, String, String> parser = (r, s) -> s;
|
||||
protected @NotNull BiFunction<RECEIVER, String, MSG> compiler = (r, s) -> {
|
||||
throw new IllegalStateException("Compiler not supplied.");
|
||||
};
|
||||
protected @NotNull BiConsumer<RECEIVER, List<MSG>> dispatcher = (r, l) -> {
|
||||
throw new IllegalStateException("Dispatcher not supplied.");
|
||||
};
|
||||
|
||||
protected Builder() {
|
||||
super(ConfigurationHolder.class, TEXT_TYPE);
|
||||
defaults(() -> defaultBuilder.build()); // Set the default value from the default builder.
|
||||
}
|
||||
|
||||
public @NotNull SELF parser(@NotNull BiFunction<RECEIVER, String, String> parser) {
|
||||
this.parser = parser;
|
||||
return self();
|
||||
}
|
||||
|
||||
public @NotNull SELF compiler(@NotNull BiFunction<RECEIVER, String, MSG> compiler) {
|
||||
this.compiler = compiler;
|
||||
return self();
|
||||
}
|
||||
|
||||
public @NotNull SELF dispatcher(@NotNull BiConsumer<RECEIVER, List<MSG>> dispatcher) {
|
||||
this.dispatcher = dispatcher;
|
||||
return self();
|
||||
}
|
||||
|
||||
public @NotNull SELF params(@NotNull String... params) {
|
||||
this.params = params;
|
||||
return self();
|
||||
}
|
||||
|
||||
public @NotNull SELF defaults(@NotNull Consumer<TextContents.Builder> consumer) {
|
||||
consumer.accept(this.defaultBuilder);
|
||||
return self();
|
||||
}
|
||||
|
||||
public @NotNull SELF defaults(@NotNull String... contents) {
|
||||
return defaults(builder -> builder.set(contents));
|
||||
}
|
||||
|
||||
public @NotNull SELF defaults(@NotNull Iterable<String> contents) {
|
||||
return defaults(builder -> builder.set(contents));
|
||||
}
|
||||
|
||||
public @NotNull SELF optional(@NotNull String id, @NotNull String... lines) {
|
||||
return defaults(builder -> builder.optional(id, lines));
|
||||
}
|
||||
|
||||
public @NotNull SELF optional(@NotNull String id, @NotNull Iterable<String> lines) {
|
||||
return defaults(builder -> builder.optional(id, lines));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ConfiguredText<MSG, RECEIVER> build() {
|
||||
return new ConfiguredText<>(buildManifest(), this.parser, this.compiler, this.dispatcher, this.params);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class StardardBuilder<MSG, RECEIVER> extends Builder<MSG, RECEIVER, StardardBuilder<MSG, RECEIVER>> {
|
||||
@Override
|
||||
protected @NotNull StardardBuilder<MSG, RECEIVER> self() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package cc.carm.lib.configuration.value.text;
|
||||
|
||||
import cc.carm.lib.configuration.value.text.data.TextContents;
|
||||
import cc.carm.lib.configuration.value.text.function.TextDispatcher;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class PreparedText<MSG, RECEIVER> extends TextDispatcher<MSG, RECEIVER, PreparedText<MSG, RECEIVER>> {
|
||||
|
||||
public PreparedText(@NotNull TextContents texts, @NotNull String... params) {
|
||||
super(texts, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedText<MSG, RECEIVER> self() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
package cc.carm.lib.configuration.value.text.data;
|
||||
|
||||
import cc.carm.lib.configuration.source.section.ConfigureSection;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class TextContents {
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public static TextContents of(@NotNull List<String> lines, @NotNull Map<String, List<String>> optional) {
|
||||
return new TextContents(lines, optional);
|
||||
}
|
||||
|
||||
protected final @NotNull List<String> lines;
|
||||
protected final @NotNull Map<String, List<String>> optional;
|
||||
|
||||
public TextContents(@NotNull List<String> lines, @NotNull Map<String, List<String>> optional) {
|
||||
this.lines = lines;
|
||||
this.optional = optional;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return lines.isEmpty() || lines.stream().allMatch(String::isEmpty);
|
||||
}
|
||||
|
||||
public @NotNull List<String> lines() {
|
||||
return lines;
|
||||
}
|
||||
|
||||
public @NotNull Map<String, List<String>> optionalLines() {
|
||||
return optional;
|
||||
}
|
||||
|
||||
public @Nullable Object serialize() {
|
||||
if (optional.isEmpty()) {
|
||||
if (lines.isEmpty()) return null;
|
||||
else if (lines.size() == 1) return lines.get(0);
|
||||
else return lines;
|
||||
} else {
|
||||
Map<String, Object> map = new LinkedHashMap<>();
|
||||
map.put("contents", lines);
|
||||
map.put("optional", optional);
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
public static @Nullable TextContents deserialize(@NotNull Object data) {
|
||||
Builder builder = builder();
|
||||
if (data instanceof String) {
|
||||
return builder.set((String) data).build();
|
||||
} else if (data instanceof List<?>) {
|
||||
((List<?>) data).stream().map(Object::toString).forEach(builder::add);
|
||||
return builder.build();
|
||||
} else if (data instanceof ConfigureSection) {
|
||||
ConfigureSection section = (ConfigureSection) data;
|
||||
builder.set(section.getStringList("contents"));
|
||||
|
||||
ConfigureSection optionalSection = section.getSection("optional");
|
||||
if (optionalSection != null) {
|
||||
for (String key : optionalSection.getKeys(false)) {
|
||||
builder.optional(key, optionalSection.getStringList(key));
|
||||
}
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
||||
protected List<String> lines = new ArrayList<>();
|
||||
protected Map<String, List<String>> optional = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Add lines to the contents
|
||||
*
|
||||
* @param lines lines to add
|
||||
* @return this builder
|
||||
*/
|
||||
public Builder add(@NotNull String... lines) {
|
||||
this.lines.addAll(Arrays.asList(lines));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add lines to the contents
|
||||
*
|
||||
* @param lines lines to add
|
||||
* @return this builder
|
||||
*/
|
||||
public Builder add(@NotNull Iterable<String> lines) {
|
||||
lines.forEach(this.lines::add);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the lines of the contents
|
||||
*
|
||||
* @param lines lines to set
|
||||
* @return this builder
|
||||
*/
|
||||
public Builder set(@NotNull String... lines) {
|
||||
this.lines = Arrays.asList(lines);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the lines of the contents
|
||||
*
|
||||
* @param lines lines to set
|
||||
* @return this builder
|
||||
*/
|
||||
public Builder set(@NotNull Iterable<String> lines) {
|
||||
this.lines = new ArrayList<>();
|
||||
lines.forEach(this.lines::add);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add optional lines to the contents
|
||||
*
|
||||
* @param key key of the optional lines
|
||||
* @param lines lines to add
|
||||
* @return this builder
|
||||
*/
|
||||
public Builder optional(@NotNull String key, @NotNull String... lines) {
|
||||
optional.put(key, Arrays.asList(lines));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add optional lines to the contents
|
||||
*
|
||||
* @param key key of the optional lines
|
||||
* @param lines lines to add
|
||||
* @return this builder
|
||||
*/
|
||||
public Builder optional(@NotNull String key, @NotNull Iterable<String> lines) {
|
||||
List<String> list = new ArrayList<>();
|
||||
lines.forEach(list::add);
|
||||
optional.put(key, list);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The built TextContents
|
||||
*/
|
||||
public TextContents build() {
|
||||
return of(lines, optional);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package cc.carm.lib.configuration.value.text.function;
|
||||
|
||||
import cc.carm.lib.configuration.value.text.data.TextContents;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
public abstract class TextCompiler<MSG, RECEIVER, SELF extends TextCompiler<MSG, RECEIVER, SELF>> extends TextParser<RECEIVER, SELF> {
|
||||
|
||||
protected BiFunction<RECEIVER, String, MSG> compiler = (receiver, value) -> null;
|
||||
|
||||
protected TextCompiler(@NotNull TextContents texts, @NotNull String... params) {
|
||||
super(texts, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the text compiler.
|
||||
*
|
||||
* @param compiler The text compiler.
|
||||
* @return The current {@link TextCompiler} instance.
|
||||
*/
|
||||
public SELF compiler(@NotNull BiFunction<RECEIVER, String, MSG> compiler) {
|
||||
this.compiler = compiler;
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile the text for specific receiver.
|
||||
*
|
||||
* @param receiver The receiver.
|
||||
* @return The compiled text.
|
||||
* @see #parse(Object, BiFunction)
|
||||
*/
|
||||
public @NotNull List<MSG> compile(@Nullable RECEIVER receiver) {
|
||||
return parse(receiver, this.compiler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile the singleton text for specific receiver.
|
||||
*
|
||||
* @param receiver The receiver.
|
||||
* @return The compiled text.
|
||||
* @see #parseLine(Object, BiFunction)
|
||||
*/
|
||||
public @Nullable MSG compileLine(@Nullable RECEIVER receiver) {
|
||||
return parseLine(receiver, this.compiler);
|
||||
}
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
package cc.carm.lib.configuration.value.text.function;
|
||||
|
||||
import cc.carm.lib.configuration.value.text.data.TextContents;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public abstract class TextDispatcher<MSG, RECEIVER, SELF extends TextDispatcher<MSG, RECEIVER, SELF>> extends TextCompiler<MSG, RECEIVER, SELF> {
|
||||
|
||||
protected @NotNull BiConsumer<RECEIVER, List<MSG>> dispatcher = (receiver, msg) -> {
|
||||
};
|
||||
|
||||
protected TextDispatcher(@NotNull TextContents texts, @NotNull String... params) {
|
||||
super(texts, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the dispatcher to send the message to the receiver
|
||||
*
|
||||
* @param dispatcher the dispatcher
|
||||
* @return {@link TextDispatcher}
|
||||
*/
|
||||
public SELF dispatcher(@NotNull BiConsumer<RECEIVER, List<MSG>> dispatcher) {
|
||||
this.dispatcher = dispatcher;
|
||||
return self();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Dispatch the message to the receiver
|
||||
*
|
||||
* @param receivers the receivers
|
||||
*/
|
||||
@SafeVarargs
|
||||
public final void to(@NotNull RECEIVER... receivers) {
|
||||
if (receivers.length == 0) return;
|
||||
to(Arrays.asList(receivers));
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch the message to the receiver
|
||||
*
|
||||
* @param receivers the receivers
|
||||
*/
|
||||
public void to(@NotNull Iterable<? extends RECEIVER> receivers) {
|
||||
for (RECEIVER receiver : receivers) {
|
||||
List<MSG> msg = compile(receiver);
|
||||
if (msg.isEmpty()) return;
|
||||
dispatcher.accept(receiver, msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch the message to the receiver
|
||||
*
|
||||
* @param receivers the receivers
|
||||
*/
|
||||
public void to(@NotNull Supplier<Iterable<? extends RECEIVER>> receivers) {
|
||||
to(receivers.get());
|
||||
}
|
||||
|
||||
}
|
||||
+298
@@ -0,0 +1,298 @@
|
||||
package cc.carm.lib.configuration.value.text.function;
|
||||
|
||||
import cc.carm.lib.configuration.value.text.data.TextContents;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.UnaryOperator;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public abstract class TextParser<RECEIVER, SELF extends TextParser<RECEIVER, SELF>> {
|
||||
|
||||
/**
|
||||
* Used to match the message insertion
|
||||
* <p>
|
||||
* format:
|
||||
* <br>- to insert parsed line {prefix}#content-id#{offset-above,offset-down}
|
||||
* <br>- to insert original line {prefix}@content-id@{offset-above,offset-down}
|
||||
* <br> example:
|
||||
* <ul>
|
||||
* <li>{- }#content-id#{1,1}</li>
|
||||
* <li>@content-id@{1,1}</li>
|
||||
* </ul>
|
||||
*/
|
||||
public static final @NotNull Pattern INSERT_PATTERN = Pattern.compile(
|
||||
"^(?:\\{(?<prefix>.*)})?(?<type>[#@])(?<id>.*)[#@](?:\\{(?<above>-?\\d+)(?:,(?<down>-?\\d+))?})?$"
|
||||
);
|
||||
|
||||
protected final @NotNull TextContents texts;
|
||||
|
||||
protected BiFunction<RECEIVER, String, String> parser = (receiver, value) -> value;
|
||||
protected String lineSeparator = System.lineSeparator();
|
||||
|
||||
/**
|
||||
* Used to store the placeholders of the message
|
||||
*/
|
||||
protected @NotNull Map<String, Object> placeholders = new HashMap<>();
|
||||
protected @NotNull UnaryOperator<String> paramBuilder = s -> "%(" + s + ")";
|
||||
protected @NotNull String[] params;
|
||||
|
||||
/**
|
||||
* Used to store the insertion of the message
|
||||
*/
|
||||
protected @NotNull Map<String, List<String>> insertion = new HashMap<>();
|
||||
protected boolean disableInsertion = false;
|
||||
|
||||
protected TextParser(@NotNull TextContents texts, @NotNull String... params) {
|
||||
this.texts = texts;
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
public abstract SELF self();
|
||||
|
||||
/**
|
||||
* Disable the insertion of the text.
|
||||
* <br> If the insertion is disabled, the text will be parsed directly.
|
||||
*
|
||||
* @return the current {@link TextParser} instance
|
||||
*/
|
||||
public SELF disableInsertion() {
|
||||
this.disableInsertion = true;
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable the insertion of the text.
|
||||
*
|
||||
* @return the current {@link TextParser} instance
|
||||
*/
|
||||
public SELF enableInsertion() {
|
||||
this.disableInsertion = false;
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the line separator for the text.
|
||||
*
|
||||
* @param lineSeparator the line separator, default is {@link System#lineSeparator()}
|
||||
* @return the current {@link TextParser} instance
|
||||
*/
|
||||
public SELF lineSeparator(@NotNull String lineSeparator) {
|
||||
this.lineSeparator = lineSeparator;
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set all the placeholders for the text.
|
||||
* <br> Will override the previous placeholders modifications.
|
||||
*
|
||||
* @param placeholders the placeholders
|
||||
* @return the current {@link TextParser} instance
|
||||
*/
|
||||
public SELF placeholders(@NotNull Map<String, Object> placeholders) {
|
||||
this.placeholders = placeholders;
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the placeholders for the text.
|
||||
*
|
||||
* @param consumer the placeholders
|
||||
* @return the current {@link TextParser} instance
|
||||
*/
|
||||
public SELF placeholders(@NotNull Consumer<Map<String, Object>> consumer) {
|
||||
consumer.accept(this.placeholders);
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the placeholders for the text.
|
||||
*
|
||||
* @param values the values of the placeholders
|
||||
* @return the current {@link TextParser} instance
|
||||
*/
|
||||
public SELF placeholders(@Nullable Object... values) {
|
||||
return placeholders(map -> map.putAll(buildParams(this.paramBuilder, this.params, values)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the placeholder for the text.
|
||||
*
|
||||
* @param key the key of the placeholder
|
||||
* @param value the value of the placeholder
|
||||
* @return the current {@link TextParser} instance
|
||||
*/
|
||||
public SELF placeholder(@NotNull String key, @Nullable Object value) {
|
||||
this.placeholders.put(paramBuilder.apply(key), value);
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the params for the text,
|
||||
* used for {@link #placeholders(Object...)} to build the placeholders.
|
||||
*
|
||||
* @param params the params
|
||||
* @return the current {@link TextParser} instance
|
||||
*/
|
||||
public SELF params(@NotNull String... params) {
|
||||
this.params = params;
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert the specific contents by the id.
|
||||
*
|
||||
* @param id the id of the insertion text
|
||||
* @param lines the lines to insert
|
||||
* @return the current {@link TextParser} instance
|
||||
*/
|
||||
public SELF insert(@NotNull String id, @NotNull String... lines) {
|
||||
this.insertion.put(id, Arrays.asList(lines));
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert the specific contents by the id.
|
||||
*
|
||||
* @param id the id of the insertion text
|
||||
* @param lines the lines to insert
|
||||
* @return the current {@link TextParser} instance
|
||||
*/
|
||||
public SELF insert(@NotNull String id, @NotNull List<String> lines) {
|
||||
this.insertion.put(id, lines);
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert the specific contents by the id.
|
||||
* <br> If the text not found in {@link TextContents#optionalLines()},
|
||||
* nothing will happen.
|
||||
*
|
||||
* @param id the id of the insertion text
|
||||
* @return the current {@link TextParser} instance
|
||||
*/
|
||||
public SELF insert(@NotNull String id) {
|
||||
List<String> lines = this.texts.optionalLines().get(id);
|
||||
if (lines == null) return self();
|
||||
else return insert(id, lines);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the parser for the text.
|
||||
*
|
||||
* @param parser The parser
|
||||
* @return The current {@link TextParser} instance
|
||||
*/
|
||||
public SELF parser(@NotNull BiFunction<RECEIVER, String, String> parser) {
|
||||
this.parser = parser;
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the texts for the receiver.
|
||||
*
|
||||
* @param receiver the receiver
|
||||
* @param compiler the compiler
|
||||
* @param <V> the type of the message
|
||||
* @return the parsed line
|
||||
*/
|
||||
public <V> List<V> parse(@Nullable RECEIVER receiver, @NotNull BiFunction<RECEIVER, String, V> compiler) {
|
||||
List<V> result = new ArrayList<>();
|
||||
handleTexts(receiver, s -> result.add(compiler.apply(receiver, s)));
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the texts as a single line for the receiver.
|
||||
*
|
||||
* @param receiver the receiver
|
||||
* @param compiler the compiler
|
||||
* @param <V> the type of the message
|
||||
* @return the parsed line
|
||||
*/
|
||||
public <V> @Nullable V parseLine(@Nullable RECEIVER receiver, @NotNull BiFunction<RECEIVER, String, V> compiler) {
|
||||
if (this.texts.isEmpty()) return null;
|
||||
StringBuilder builder = new StringBuilder();
|
||||
handleTexts(receiver, s -> builder.append(s).append(this.lineSeparator));
|
||||
// Remove the last line separator, if it exists
|
||||
if (builder.length() > 0) builder.delete(builder.length() - this.lineSeparator.length(), builder.length());
|
||||
return compiler.apply(receiver, builder.toString());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse the supplied single text for the receiver.
|
||||
*
|
||||
* @param receiver the receiver
|
||||
* @param text the text to parse
|
||||
* @return the parsed text
|
||||
*/
|
||||
protected @Nullable String parseText(@Nullable RECEIVER receiver, @NotNull String text) {
|
||||
return this.parser.apply(receiver, setPlaceholders(text, this.placeholders));
|
||||
}
|
||||
|
||||
|
||||
public void handleTexts(@Nullable RECEIVER receiver, @NotNull Consumer<String> lineConsumer) {
|
||||
if (this.texts.isEmpty()) return; // Nothing to parse
|
||||
|
||||
if (this.disableInsertion) {
|
||||
this.texts.lines().forEach(line -> lineConsumer.accept(parseText(receiver, line)));
|
||||
return; // Simple parsed
|
||||
}
|
||||
|
||||
for (String line : this.texts.lines()) {
|
||||
Matcher matcher = INSERT_PATTERN.matcher(line);
|
||||
if (!matcher.matches()) {
|
||||
lineConsumer.accept(parseText(receiver, line));
|
||||
continue;
|
||||
}
|
||||
|
||||
String id = matcher.group("id");
|
||||
List<String> values = this.insertion.get(id);
|
||||
if (values == null) continue;
|
||||
|
||||
String prefix = matcher.group("prefix");
|
||||
String type = matcher.group("type");
|
||||
boolean original = type.equals("@");
|
||||
int offsetAbove = Optional.ofNullable(matcher.group("above"))
|
||||
.map(Integer::parseInt).orElse(0);
|
||||
int offsetDown = Optional.ofNullable(matcher.group("down"))
|
||||
.map(Integer::parseInt).orElse(offsetAbove); // If offsetDown is not set, use offsetAbove
|
||||
|
||||
IntStream.range(0, Math.max(0, offsetAbove)).mapToObj(i -> "").forEach(lineConsumer);
|
||||
String prefixContent = Optional.ofNullable(prefix).map(p -> parseText(receiver, p)).orElse("");
|
||||
if (original) {
|
||||
values.stream().map(value -> prefixContent + value).forEach(lineConsumer);
|
||||
} else {
|
||||
values.stream().map(value -> prefixContent + parseText(receiver, value)).forEach(lineConsumer);
|
||||
}
|
||||
IntStream.range(0, Math.max(0, offsetDown)).mapToObj(i -> "").forEach(lineConsumer);
|
||||
}
|
||||
}
|
||||
|
||||
public static String setPlaceholders(@NotNull String messages,
|
||||
@NotNull Map<String, Object> placeholders) {
|
||||
if (messages.isEmpty()) return messages;
|
||||
String parsed = messages;
|
||||
for (Map.Entry<String, Object> entry : placeholders.entrySet()) {
|
||||
parsed = parsed.replace(entry.getKey(), entry.getValue() == null ? "" : entry.getValue().toString());
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
|
||||
public static Map<String, Object> buildParams(@NotNull UnaryOperator<String> paramBuilder,
|
||||
@Nullable String[] params, @Nullable Object[] values) {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
if (params == null || params.length == 0) return map;
|
||||
for (int i = 0; i < params.length; i++) {
|
||||
map.put(paramBuilder.apply(params[i]), (values != null && values.length > i) ? values[i] : "?");
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
package cc.carm.lib.configuration.value.text.tests;
|
||||
|
||||
|
||||
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
||||
import cc.carm.lib.configuration.source.yaml.YAMLConfigFactory;
|
||||
import cc.carm.lib.configuration.value.text.tests.conf.AppMessages;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ConfigTest {
|
||||
|
||||
|
||||
public static final String[] WEBSITES = new String[]{
|
||||
"https://carm.cc",
|
||||
"https://www.baidu.com",
|
||||
"https://www.google.com"
|
||||
};
|
||||
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
|
||||
ConfigurationHolder<?> holder = YAMLConfigFactory.from("target/messages.yml").build();
|
||||
|
||||
holder.initialize(AppMessages.class);
|
||||
|
||||
System.out.println("--------------------------");
|
||||
|
||||
AppMessages.WELCOME.prepare()
|
||||
.placeholders("Carm")
|
||||
.insert("guidance")
|
||||
.insert("websites", WEBSITES)
|
||||
.to(System.out);
|
||||
|
||||
System.out.println("--------------------------");
|
||||
|
||||
AppMessages.NOT_AVAILABLE.sendTo(System.out);
|
||||
|
||||
System.out.println("--------------------------");
|
||||
|
||||
AppMessages.NO_PERMISSION.sendTo(System.out);
|
||||
|
||||
System.out.println("--------------------------");
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package cc.carm.lib.configuration.value.text.tests;
|
||||
|
||||
import cc.carm.lib.configuration.value.text.PreparedText;
|
||||
import cc.carm.lib.configuration.value.text.data.TextContents;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.*;
|
||||
|
||||
public class ParseTest {
|
||||
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
|
||||
List<String> lines = new ArrayList<>();
|
||||
lines.add("Hello, %(name)");
|
||||
lines.add("#more-creating#{1}");
|
||||
lines.add("This is a test message");
|
||||
lines.add("#guidance#");
|
||||
lines.add("{- }#websites#{0,1}");
|
||||
lines.add("Thanks for your reading!");
|
||||
|
||||
|
||||
Map<String, List<String>> optional = new HashMap<>();
|
||||
optional.put("guidance", Arrays.asList("To get more information for %(name), see:"));
|
||||
optional.put("websites", Arrays.asList("https://www.baidu.com", "https://www.google.com"));
|
||||
|
||||
TextContents textContents = new TextContents(lines, optional);
|
||||
|
||||
PreparedText<String, PrintStream> msg = new PreparedText<String, PrintStream>(textContents)
|
||||
.dispatcher((p, s) -> s.forEach(p::println))
|
||||
.parser((p, s) -> s)
|
||||
.compiler((p, s) -> s);
|
||||
|
||||
msg.placeholder("name", "Carm")
|
||||
.insert("guidance")
|
||||
.insert("websites", "Baidu", "Bilibili", "Google");
|
||||
|
||||
System.out.println("----------------------------");
|
||||
msg.to(System.out);
|
||||
System.out.println("----------------------------");
|
||||
System.out.println(msg.compileLine(System.out));
|
||||
System.out.println("----------------------------");
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package cc.carm.lib.configuration.value.text.tests.conf;
|
||||
|
||||
import cc.carm.lib.configuration.Configuration;
|
||||
import cc.carm.lib.configuration.annotation.ConfigPath;
|
||||
|
||||
@ConfigPath(root = true)
|
||||
public interface AppMessages extends Configuration {
|
||||
|
||||
ConfiguredMsg WELCOME = ConfiguredMsg.builder()
|
||||
.defaults(
|
||||
"Hello, %(name)",
|
||||
"#more-creating#{1}",
|
||||
"This is a test message",
|
||||
"#guidance#",
|
||||
"{- }#websites#{0,1}",
|
||||
"Thanks for your reading!")
|
||||
.optional("guidance", "To get more information for %(name), see:")
|
||||
.params("name").build();
|
||||
|
||||
ConfiguredMsg NO_PERMISSION = ConfiguredMsg.builder()
|
||||
.defaults("Sorry! But you don't have permissions to do this.")
|
||||
.build();
|
||||
|
||||
ConfiguredMsg NOT_AVAILABLE = ConfiguredMsg.builder()
|
||||
.defaults("Error! Service is not available now.", "Please contact your system manager.")
|
||||
.build();
|
||||
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
package cc.carm.lib.configuration.value.text.tests.conf;
|
||||
|
||||
import cc.carm.lib.configuration.value.ValueManifest;
|
||||
import cc.carm.lib.configuration.value.text.ConfiguredText;
|
||||
import cc.carm.lib.configuration.value.text.data.TextContents;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.PrintStream;
|
||||
|
||||
public class ConfiguredMsg extends ConfiguredText<String, PrintStream> {
|
||||
|
||||
public static @NotNull MsgBuilder builder() {
|
||||
return new MsgBuilder();
|
||||
}
|
||||
|
||||
public static @NotNull ConfiguredMsg of(@NotNull String... text) {
|
||||
return builder().defaults(text).build();
|
||||
}
|
||||
|
||||
public ConfiguredMsg(@NotNull ValueManifest<TextContents> manifest, @NotNull String[] params) {
|
||||
super(
|
||||
manifest,
|
||||
(p, s) -> s,
|
||||
(p, s) -> s,
|
||||
(p, s) -> s.forEach(p::println),
|
||||
params
|
||||
);
|
||||
}
|
||||
|
||||
public void print(@NotNull Object... values) {
|
||||
sendTo(System.out, values);
|
||||
}
|
||||
|
||||
public static class MsgBuilder extends Builder<String, PrintStream, MsgBuilder> {
|
||||
|
||||
@Override
|
||||
protected @NotNull MsgBuilder self() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ConfiguredMsg build() {
|
||||
return new ConfiguredMsg(buildManifest(), params);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user