Skip to content

Commit 61d4362

Browse files
committed
Replace Template input/output Map with Values
1 parent 9b2711c commit 61d4362

File tree

10 files changed

+169
-48
lines changed

10 files changed

+169
-48
lines changed

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ Token token = Token.of("[a-zA-Z]+");
2727
Template template = Template.of("Hello ${name}!")
2828
.withToken("name", token);
2929

30-
Map<String, String> values = Map.of("name", "World");
30+
Values values = Values.of("name", "World");
3131
String output = template.format(values);
3232

3333
System.out.println(output);
@@ -43,7 +43,7 @@ Token token = Token.of("[a-zA-Z]+");
4343
Template template = Template.of("Hello ${name}!")
4444
.withToken("name", token);
4545

46-
Map<String, String> data = template.parse("Hello World!");
46+
Values data = template.parse("Hello World!");
4747

4848
System.out.println(data);
4949
```
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package io.github.noncat_lang;
22

3-
import java.util.Map;
4-
53
import io.github.noncat_lang.internal.TemplateImpl;
64

75
public interface Template {
@@ -12,10 +10,10 @@ static Template of(String templateString) {
1210

1311
Template withToken(String field, Token token);
1412

15-
String format(Map<String, String> values);
13+
String format(Values values);
1614

17-
String unparse(Map<String, String> values);
15+
String unparse(Values values);
1816

19-
Map<String, String> parse(String value);
17+
Values parse(String value);
2018

2119
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package io.github.noncat_lang;
2+
3+
import java.util.Map;
4+
import java.util.Optional;
5+
6+
import io.github.noncat_lang.internal.ValuesImpl;
7+
8+
public interface Values {
9+
10+
static Values create() {
11+
return of();
12+
}
13+
14+
static Values of() {
15+
return ValuesImpl.of();
16+
}
17+
18+
static Values of(String field, String value) {
19+
return of().set(field, value);
20+
}
21+
22+
static Values of(Map<String, String> values) {
23+
return of().setAll(values);
24+
}
25+
26+
Values set(String field, String value);
27+
28+
Values setAll(Map<String, String> values);
29+
30+
Optional<String> get(String field);
31+
32+
int size();
33+
34+
}

src/main/java/io/github/noncat_lang/internal/DecodingImpl.java

+2-5
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
package io.github.noncat_lang.internal;
22

33
import io.github.noncat_lang.Decoding;
4-
import lombok.AccessLevel;
5-
import lombok.AllArgsConstructor;
64
import lombok.NonNull;
7-
import lombok.experimental.FieldDefaults;
5+
import lombok.Value;
86

9-
@AllArgsConstructor(staticName = "of")
10-
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
7+
@Value(staticConstructor = "of")
118
public final class DecodingImpl implements Decoding {
129
@NonNull
1310
String regex;

src/main/java/io/github/noncat_lang/internal/EncodingImpl.java

+2-5
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
package io.github.noncat_lang.internal;
22

33
import io.github.noncat_lang.Encoding;
4-
import lombok.AccessLevel;
5-
import lombok.AllArgsConstructor;
64
import lombok.NonNull;
7-
import lombok.experimental.FieldDefaults;
5+
import lombok.Value;
86

9-
@AllArgsConstructor(staticName = "of")
10-
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
7+
@Value(staticConstructor = "of")
118
public final class EncodingImpl implements Encoding {
129
@NonNull
1310
String regex;

src/main/java/io/github/noncat_lang/internal/TemplateImpl.java

+10-12
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,13 @@
1717
import io.github.noncat_lang.TemplateParser.ElementContext;
1818
import io.github.noncat_lang.TemplateParser.TemplateContext;
1919
import io.github.noncat_lang.Token;
20+
import io.github.noncat_lang.Values;
2021
import io.github.noncat_lang.exceptions.MissingTokenException;
2122
import io.github.noncat_lang.exceptions.MissingValueException;
22-
import lombok.AccessLevel;
23-
import lombok.AllArgsConstructor;
2423
import lombok.NonNull;
25-
import lombok.experimental.FieldDefaults;
24+
import lombok.Value;
2625

27-
@AllArgsConstructor(access = AccessLevel.PRIVATE)
28-
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
26+
@Value
2927
public final class TemplateImpl implements Template {
3028
TemplateContext parseTree;
3129
Map<String, Token> tokens = new HashMap<>();
@@ -49,27 +47,27 @@ public TemplateImpl withToken(@NonNull String field, @NonNull Token token) {
4947
}
5048

5149
@Override
52-
public String format(@NonNull Map<String, String> values) {
50+
public String format(@NonNull Values values) {
5351
return unparse(values);
5452
}
5553

5654
@Override
57-
public String unparse(@NonNull Map<String, String> values) {
55+
public String unparse(@NonNull Values values) {
5856
return parseTree.element().stream().map(element -> unparseElement(element, values)).collect(Collectors.joining());
5957
}
6058

61-
private String unparseElement(ElementContext element, Map<String, String> values) {
59+
private String unparseElement(ElementContext element, Values values) {
6260
ArgContext arg = element.arg();
6361
return arg == null ? element.TEXT().getText() : unparseArg(arg, values);
6462
}
6563

66-
private String unparseArg(ArgContext arg, @NonNull Map<String, String> values) {
64+
private String unparseArg(ArgContext arg, @NonNull Values values) {
6765
String id = getId(arg);
6866
Token token = tokens.get(id);
6967
if (token == null) {
7068
throw new MissingTokenException(String.format("Token for field '%s' is missing", id));
7169
}
72-
String value = values.get(id);
70+
String value = values.get(id).orElse(null);
7371
if (value == null) {
7472
throw new MissingValueException(String.format("Value for field '%s' is missing", id));
7573
}
@@ -78,14 +76,14 @@ private String unparseArg(ArgContext arg, @NonNull Map<String, String> values) {
7876
}
7977

8078
@Override
81-
public Map<String, String> parse(@NonNull String value) {
79+
public Values parse(@NonNull String value) {
8280
String pattern = parseTree.element().stream().map(this::parseElement).collect(Collectors.joining());
8381
Matcher matcher = Pattern.compile(pattern).matcher(value);
8482
if (!matcher.matches()) {
8583
throw new IllegalArgumentException(
8684
String.format("Error during parsing: value '%s' does not match pattern '%s'", value, pattern));
8785
}
88-
return decodeAllToken(matcher);
86+
return Values.of(decodeAllToken(matcher));
8987
}
9088

9189
private Map<String, String> decodeAllToken(Matcher matcher) {

src/main/java/io/github/noncat_lang/internal/TokenImpl.java

+2-7
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,12 @@
99
import io.github.noncat_lang.Decoding;
1010
import io.github.noncat_lang.Encoding;
1111
import io.github.noncat_lang.Token;
12-
import lombok.AccessLevel;
13-
import lombok.AllArgsConstructor;
14-
import lombok.Getter;
1512
import lombok.NonNull;
16-
import lombok.experimental.FieldDefaults;
13+
import lombok.Value;
1714

18-
@AllArgsConstructor(access = AccessLevel.PRIVATE)
19-
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
15+
@Value
2016
public final class TokenImpl implements Token {
2117
@NonNull
22-
@Getter
2318
String regex;
2419
List<Encoding> encodings = new ArrayList<>();
2520
List<Decoding> decodings = new ArrayList<>();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package io.github.noncat_lang.internal;
2+
3+
import java.util.HashMap;
4+
import java.util.Map;
5+
import java.util.Optional;
6+
7+
import io.github.noncat_lang.Values;
8+
import lombok.Value;
9+
10+
@Value(staticConstructor = "of")
11+
public final class ValuesImpl implements Values {
12+
Map<String, String> data = new HashMap<>();
13+
14+
@Override
15+
public Values set(String field, String value) {
16+
data.put(field, value);
17+
return this;
18+
}
19+
20+
@Override
21+
public Values setAll(Map<String, String> values) {
22+
data.putAll(values);
23+
return this;
24+
}
25+
26+
@Override
27+
public Optional<String> get(String field) {
28+
return Optional.ofNullable(data.get(field));
29+
}
30+
31+
@Override
32+
public int size() {
33+
return data.size();
34+
}
35+
36+
}

src/test/java/io/github/noncat_lang/TemplateTest.java

+13-12
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ void formatSimple() {
2222
Token token = Token.of("[a-zA-Z]+");
2323
Template template = Template.of("Hello ${world}!").withToken("world", token);
2424
// when
25-
Map<String, String> values = Map.of("world", "LangSec");
25+
Values values = Values.of("world", "LangSec");
2626
String result = template.format(values);
2727
// then
2828
assertThat(result).isEqualTo("Hello LangSec!");
@@ -44,7 +44,7 @@ void unparse(String regex, String templateString, String field, String value, St
4444
Token token = Token.of(regex);
4545
Template template = Template.of(templateString).withToken(field, token);
4646
// when
47-
Map<String, String> values = Map.of(field, value);
47+
Values values = Values.of(field, value);
4848
String result = template.unparse(values);
4949
// then
5050
assertThat(result).isEqualTo(expected);
@@ -57,9 +57,9 @@ void parse(String regex, String templateString, String field, String expected, S
5757
Token token = Token.of(regex);
5858
Template template = Template.of(templateString).withToken(field, token);
5959
// when
60-
Map<String, String> result = template.parse(value);
60+
Values result = template.parse(value);
6161
// then
62-
assertThat(result).containsEntry(field, expected);
62+
assertThat(result.get(field)).hasValue(expected);
6363
}
6464

6565
@Test
@@ -68,7 +68,7 @@ void unparseMultipleFields() {
6868
Token token = Token.of("[a-zA-Z]+");
6969
Template template = Template.of("${a}, ${b}!").withToken("a", token).withToken("b", token);
7070
// when
71-
Map<String, String> values = Map.of("a", "foo", "b", "bar");
71+
Values values = Values.of(Map.of("a", "foo", "b", "bar"));
7272
String result = template.unparse(values);
7373
// then
7474
assertThat(result).isEqualTo("foo, bar!");
@@ -80,7 +80,7 @@ void unparseWithEncoding() {
8080
Token token = Token.of("'[a-zA-Z]+'").withEncoding(Encoding.of(".+", "'$0'"));
8181
Template template = Template.of("Hello ${world}!").withToken("world", token);
8282
// when
83-
Map<String, String> values = Map.of("world", "LangSec");
83+
Values values = Values.of("world", "LangSec");
8484
String result = template.unparse(values);
8585
// then
8686
assertThat(result).isEqualTo("Hello 'LangSec'!");
@@ -92,9 +92,10 @@ void parseMultipleFields() {
9292
Token token = Token.of("[a-zA-Z]+");
9393
Template template = Template.of("${a}, ${b}!").withToken("a", token).withToken("b", token);
9494
// when
95-
Map<String, String> result = template.parse("foo, bar!");
95+
Values result = template.parse("foo, bar!");
9696
// then
97-
assertThat(result).containsEntry("a", "foo").containsEntry("b", "bar");
97+
assertThat(result.get("a")).hasValue("foo");
98+
assertThat(result.get("b")).hasValue("bar");
9899
}
99100

100101
@Test
@@ -103,23 +104,23 @@ void parseWithDecoding() {
103104
Token token = Token.of("'[a-zA-Z]+'").withDecoding(Decoding.of("'", ""));
104105
Template template = Template.of("Hello ${world}!").withToken("world", token);
105106
// when
106-
Map<String, String> result = template.parse("Hello 'LangSec'!");
107+
Values result = template.parse("Hello 'LangSec'!");
107108
// then
108-
assertThat(result).containsEntry("world", "LangSec");
109+
assertThat(result.get("world")).hasValue("LangSec");
109110
}
110111

111112
@Test
112113
void unparseWithMissingToken() {
113114
Template template = Template.of("${any}");
114-
Map<String, String> values = Map.of("any", "any");
115+
Values values = Values.of("any", "any");
115116
assertThatThrownBy(() -> template.unparse(values)).isExactlyInstanceOf(MissingTokenException.class)
116117
.hasMessage("Token for field 'any' is missing");
117118
}
118119

119120
@Test
120121
void unparseWithMissingValue() {
121122
Template template = Template.of("${any}").withToken("any", Token.of("[a-z]+"));
122-
Map<String, String> values = Map.of();
123+
Values values = Values.of();
123124
assertThatThrownBy(() -> template.unparse(values)).isExactlyInstanceOf(MissingValueException.class)
124125
.hasMessage("Value for field 'any' is missing");
125126
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package io.github.noncat_lang;
2+
3+
import static org.assertj.core.api.Assertions.assertThat;
4+
5+
import java.util.Map;
6+
7+
import org.junit.jupiter.api.Test;
8+
9+
class ValuesTest {
10+
11+
@Test
12+
void empty() {
13+
// given
14+
// when
15+
Values values = Values.of();
16+
// then
17+
assertThat(values.size()).isEqualTo(0);
18+
}
19+
20+
@Test
21+
void OptionalEmptyWhenFieldNotFound() {
22+
// given
23+
// when
24+
Values values = Values.create();
25+
// then
26+
assertThat(values.get("nope")).isEmpty();
27+
}
28+
29+
void initializedWithData() {
30+
// given
31+
// when
32+
Values values = Values.of("foo", "bar");
33+
// then
34+
assertThat(values.get("foo")).hasValue("bar");
35+
}
36+
37+
void initializedFromMap() {
38+
// given
39+
// when
40+
Values values = Values.of(Map.of("foo", "bar"));
41+
// then
42+
assertThat(values.get("foo")).hasValue("bar");
43+
}
44+
45+
@Test
46+
void setData() {
47+
// given
48+
Values values = Values.of();
49+
// when
50+
values.set("foo", "bar");
51+
// then
52+
assertThat(values.get("foo")).hasValue("bar");
53+
}
54+
55+
@Test
56+
void setDataFromMap() {
57+
// given
58+
Values values = Values.of();
59+
// when
60+
values.setAll(Map.of("foo", "bar"));
61+
// then
62+
assertThat(values.get("foo")).hasValue("bar");
63+
}
64+
65+
}

0 commit comments

Comments
 (0)