Skip to content

Commit 9b2711c

Browse files
committed
Add internal package, add interfaces
1 parent 93afa37 commit 9b2711c

File tree

8 files changed

+270
-180
lines changed

8 files changed

+270
-180
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,13 @@
11
package io.github.noncat_lang;
22

3-
import lombok.AccessLevel;
4-
import lombok.AllArgsConstructor;
5-
import lombok.NonNull;
6-
import lombok.experimental.FieldDefaults;
3+
import io.github.noncat_lang.internal.DecodingImpl;
74

8-
@AllArgsConstructor(staticName = "of")
9-
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
10-
public class Decoding {
11-
@NonNull
12-
String regex;
13-
@NonNull
14-
String replacement;
5+
public interface Decoding {
156

16-
String decode(@NonNull String value) {
17-
return value.replaceAll(regex, replacement);
7+
static Decoding of(String regex, String replacement) {
8+
return DecodingImpl.of(regex, replacement);
189
}
1910

11+
String decode(String value);
12+
2013
}
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,13 @@
11
package io.github.noncat_lang;
22

3-
import lombok.AccessLevel;
4-
import lombok.AllArgsConstructor;
5-
import lombok.NonNull;
6-
import lombok.experimental.FieldDefaults;
3+
import io.github.noncat_lang.internal.EncodingImpl;
74

8-
@AllArgsConstructor(staticName = "of")
9-
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
10-
public class Encoding {
11-
@NonNull
12-
String regex;
13-
@NonNull
14-
String replacement;
5+
public interface Encoding {
156

16-
String encode(@NonNull String value) {
17-
return value.replaceAll(regex, replacement);
7+
static Encoding of(String regex, String replacement) {
8+
return EncodingImpl.of(regex, replacement);
189
}
1910

11+
String encode(String value);
12+
2013
}
Original file line numberDiff line numberDiff line change
@@ -1,110 +1,21 @@
11
package io.github.noncat_lang;
22

3-
import java.util.HashMap;
43
import java.util.Map;
5-
import java.util.Map.Entry;
6-
import java.util.regex.Matcher;
7-
import java.util.regex.Pattern;
8-
import java.util.stream.Collectors;
94

10-
import org.antlr.v4.runtime.CharStreams;
11-
import org.antlr.v4.runtime.CommonTokenStream;
5+
import io.github.noncat_lang.internal.TemplateImpl;
126

13-
import io.github.noncat_lang.TemplateParser.ArgContext;
14-
import io.github.noncat_lang.TemplateParser.ElementContext;
15-
import io.github.noncat_lang.TemplateParser.TemplateContext;
16-
import io.github.noncat_lang.exceptions.MissingTokenException;
17-
import io.github.noncat_lang.exceptions.MissingValueException;
18-
import lombok.AccessLevel;
19-
import lombok.AllArgsConstructor;
20-
import lombok.NonNull;
21-
import lombok.experimental.FieldDefaults;
7+
public interface Template {
228

23-
@AllArgsConstructor(access = AccessLevel.PRIVATE)
24-
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
25-
public class Template {
26-
TemplateContext parseTree;
27-
Map<String, Token> tokens = new HashMap<>();
28-
29-
public static Template of(@NonNull String templateString) {
30-
TemplateLexer lexer = new TemplateLexer(CharStreams.fromString(templateString));
31-
TemplateParser parser = new TemplateParser(new CommonTokenStream(lexer));
32-
return new Template(parser.template());
33-
}
34-
35-
public Template withToken(@NonNull String field, @NonNull Token token) {
36-
if (field.isBlank()) {
37-
throw new IllegalArgumentException("Token field should not be blank/empty");
38-
}
39-
if (!field.matches("[a-zA-Z0-9]+")) {
40-
throw new IllegalArgumentException("Token field does not match pattern [a-zA-Z0-9]+");
41-
}
42-
tokens.put(field, token);
43-
return this;
44-
}
45-
46-
public String format(@NonNull Map<String, String> values) {
47-
return unparse(values);
9+
static Template of(String templateString) {
10+
return TemplateImpl.of(templateString);
4811
}
4912

50-
public String unparse(@NonNull Map<String, String> values) {
51-
return parseTree.element().stream().map(element -> unparseElement(element, values)).collect(Collectors.joining());
52-
}
13+
Template withToken(String field, Token token);
5314

54-
private String unparseElement(ElementContext element, Map<String, String> values) {
55-
ArgContext arg = element.arg();
56-
return arg == null ? element.TEXT().getText() : unparseArg(arg, values);
57-
}
15+
String format(Map<String, String> values);
5816

59-
private String unparseArg(ArgContext arg, @NonNull Map<String, String> values) {
60-
String id = getId(arg);
61-
Token token = tokens.get(id);
62-
if (token == null) {
63-
throw new MissingTokenException(String.format("Token for field '%s' is missing", id));
64-
}
65-
String value = values.get(id);
66-
if (value == null) {
67-
throw new MissingValueException(String.format("Value for field '%s' is missing", id));
68-
}
69-
value = token.encode(value);
70-
return value;
71-
}
72-
73-
public Map<String, String> parse(@NonNull String value) {
74-
String pattern = parseTree.element().stream().map(this::parseElement).collect(Collectors.joining());
75-
Matcher matcher = Pattern.compile(pattern).matcher(value);
76-
if (!matcher.matches()) {
77-
throw new IllegalArgumentException(
78-
String.format("Error during parsing: value '%s' does not match pattern '%s'", value, pattern));
79-
}
80-
return decodeAllToken(matcher);
81-
}
17+
String unparse(Map<String, String> values);
8218

83-
private Map<String, String> decodeAllToken(Matcher matcher) {
84-
return tokens.entrySet().stream().collect(Collectors.toMap(Entry::getKey, entry -> decodeToken(entry, matcher)));
85-
}
86-
87-
private String decodeToken(Entry<String, Token> entry, Matcher matcher) {
88-
return entry.getValue().decode(matcher.group("x" + entry.getKey()));
89-
}
90-
91-
private String parseElement(ElementContext element) {
92-
ArgContext id = element.arg();
93-
return id == null ? Pattern.quote(element.TEXT().getText()) : parseArg(id);
94-
}
95-
96-
private String parseArg(ArgContext arg) {
97-
String id = getId(arg);
98-
Token token = tokens.get(id);
99-
if (token == null) {
100-
throw new MissingTokenException(String.format("Token for field '%s' is missing", id));
101-
}
102-
return String.format("(?<x%s>%s)", id, token.getRegex());
103-
}
104-
105-
private String getId(ArgContext arg) {
106-
String id = arg.ID().getText();
107-
return id.substring(2, id.length() - 1);
108-
}
19+
Map<String, String> parse(String value);
10920

11021
}
+11-57
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,23 @@
11
package io.github.noncat_lang;
22

3-
import static java.lang.String.format;
3+
import io.github.noncat_lang.internal.TokenImpl;
44

5-
import java.util.ArrayList;
6-
import java.util.List;
7-
import java.util.stream.Stream;
5+
public interface Token {
86

9-
import lombok.AccessLevel;
10-
import lombok.AllArgsConstructor;
11-
import lombok.Getter;
12-
import lombok.NonNull;
13-
import lombok.experimental.FieldDefaults;
14-
15-
@AllArgsConstructor(access = AccessLevel.PRIVATE)
16-
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
17-
public class Token {
18-
@NonNull
19-
@Getter(AccessLevel.PACKAGE)
20-
String regex;
21-
List<Encoding> encodings = new ArrayList<>();
22-
List<Decoding> decodings = new ArrayList<>();
23-
24-
public static Token of(@NonNull String regex) {
25-
if (regex.isBlank()) {
26-
throw new IllegalArgumentException("Token regex should not be blank/empty");
27-
}
28-
return new Token(regex);
7+
static Token of(String regex) {
8+
return TokenImpl.of(regex);
299
}
3010

31-
public Token withEncoding(@NonNull Encoding... encoding) {
32-
Stream.of(encoding).forEach(encodings::add);
33-
return this;
34-
}
11+
Token withEncoding(Encoding... encoding);
3512

36-
public Token withDecoding(@NonNull Decoding... decoding) {
37-
Stream.of(decoding).forEach(decodings::add);
38-
return this;
39-
}
13+
Token withDecoding(Decoding... decoding);
4014

41-
boolean validate(@NonNull String value) {
42-
return value.matches(regex);
43-
}
15+
String getRegex();
4416

45-
String encode(@NonNull String value) {
46-
String result = value;
47-
for (Encoding encoding : encodings) {
48-
result = encoding.encode(result);
49-
}
50-
if (!validate(result)) {
51-
throw new IllegalArgumentException(
52-
format("Error after encoding: value '%s' does not match token '%s'", result, regex));
53-
}
54-
return result;
55-
}
17+
boolean validate(String value);
5618

57-
String decode(@NonNull String value) {
58-
if (!validate(value)) {
59-
throw new IllegalArgumentException(
60-
format("Error before decoding: value '%s' does not match token '%s'", value, regex));
61-
}
62-
String result = value;
63-
for (Decoding decoding : decodings) {
64-
result = decoding.decode(result);
65-
}
66-
return result;
67-
}
19+
String encode(String value);
20+
21+
String decode(String value);
6822

6923
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package io.github.noncat_lang.internal;
2+
3+
import io.github.noncat_lang.Decoding;
4+
import lombok.AccessLevel;
5+
import lombok.AllArgsConstructor;
6+
import lombok.NonNull;
7+
import lombok.experimental.FieldDefaults;
8+
9+
@AllArgsConstructor(staticName = "of")
10+
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
11+
public final class DecodingImpl implements Decoding {
12+
@NonNull
13+
String regex;
14+
@NonNull
15+
String replacement;
16+
17+
@Override
18+
public String decode(@NonNull String value) {
19+
return value.replaceAll(regex, replacement);
20+
}
21+
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package io.github.noncat_lang.internal;
2+
3+
import io.github.noncat_lang.Encoding;
4+
import lombok.AccessLevel;
5+
import lombok.AllArgsConstructor;
6+
import lombok.NonNull;
7+
import lombok.experimental.FieldDefaults;
8+
9+
@AllArgsConstructor(staticName = "of")
10+
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
11+
public final class EncodingImpl implements Encoding {
12+
@NonNull
13+
String regex;
14+
@NonNull
15+
String replacement;
16+
17+
@Override
18+
public String encode(@NonNull String value) {
19+
return value.replaceAll(regex, replacement);
20+
}
21+
22+
}

0 commit comments

Comments
 (0)