Skip to content

Commit 4134c00

Browse files
committed
Add filter which converts a map with camelCase attributes into one that also accepts snake_case keys
1 parent 189046b commit 4134c00

4 files changed

Lines changed: 115 additions & 0 deletions

File tree

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package com.hubspot.jinjava.lib.filter;
2+
3+
import com.hubspot.jinjava.doc.annotations.JinjavaDoc;
4+
import com.hubspot.jinjava.doc.annotations.JinjavaParam;
5+
import com.hubspot.jinjava.doc.annotations.JinjavaSnippet;
6+
import com.hubspot.jinjava.interpret.JinjavaInterpreter;
7+
import com.hubspot.jinjava.objects.collections.PyMap;
8+
import com.hubspot.jinjava.objects.collections.SizeLimitingPyMap;
9+
import com.hubspot.jinjava.objects.collections.SnakeCaseAccessibleMap;
10+
import java.util.Map;
11+
12+
@JinjavaDoc(
13+
value = "Allow keys on the provided camelCase map to be accessed using snake_case",
14+
input = @JinjavaParam(
15+
value = "map",
16+
type = "dict",
17+
desc = "The dict to make keys accessible using snake_case",
18+
required = true
19+
),
20+
snippets = { @JinjavaSnippet(code = "{{ {'fooBar': 'baz'}|allow_snake_case }}") }
21+
)
22+
public class AllowSnakeCaseFilter implements Filter {
23+
public static final String NAME = "allow_snake_case";
24+
25+
@Override
26+
public String getName() {
27+
return NAME;
28+
}
29+
30+
@Override
31+
public Object filter(Object var, JinjavaInterpreter interpreter, String... args) {
32+
if (!(var instanceof Map)) {
33+
return var;
34+
}
35+
Map<String, Object> map = (Map<String, Object>) var;
36+
if (map instanceof PyMap) {
37+
map = ((PyMap) map).toMap();
38+
}
39+
return new SnakeCaseAccessibleMap(
40+
new SizeLimitingPyMap(map, interpreter.getConfig().getMaxMapSize())
41+
);
42+
}
43+
}

src/main/java/com/hubspot/jinjava/lib/filter/FilterLibrary.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ protected void registerDefaults() {
3232
registerClasses(
3333
AbsFilter.class,
3434
AddFilter.class,
35+
AllowSnakeCaseFilter.class,
3536
AttrFilter.class,
3637
Base64DecodeFilter.class,
3738
Base64EncodeFilter.class,
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package com.hubspot.jinjava.objects.collections;
2+
3+
import com.google.common.base.CaseFormat;
4+
import com.hubspot.jinjava.lib.filter.AllowSnakeCaseFilter;
5+
import com.hubspot.jinjava.objects.serialization.PyishSerializable;
6+
import java.io.IOException;
7+
import java.util.Map;
8+
9+
public class SnakeCaseAccessibleMap extends PyMap implements PyishSerializable {
10+
11+
public SnakeCaseAccessibleMap(Map<String, Object> map) {
12+
super(map);
13+
}
14+
15+
@Override
16+
public Object get(Object key) {
17+
Object result = super.get(key);
18+
if (result == null && key instanceof String) {
19+
return getWithCamelCase((String) key);
20+
}
21+
return result;
22+
}
23+
24+
private Object getWithCamelCase(String key) {
25+
if (key == null) {
26+
return null;
27+
}
28+
if (key.indexOf('_') == -1) {
29+
return null;
30+
}
31+
return super.get(CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, key));
32+
}
33+
34+
@SuppressWarnings("unchecked")
35+
@Override
36+
public <T extends Appendable & CharSequence> T appendPyishString(T appendable)
37+
throws IOException {
38+
return (T) appendable
39+
.append(PyishSerializable.writeValueAsString(toMap()))
40+
.append('|')
41+
.append(AllowSnakeCaseFilter.NAME);
42+
}
43+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.hubspot.jinjava.lib.filter;
2+
3+
import static org.assertj.core.api.Assertions.assertThat;
4+
5+
import com.hubspot.jinjava.BaseInterpretingTest;
6+
import com.hubspot.jinjava.objects.serialization.PyishObjectMapper;
7+
import org.junit.Test;
8+
9+
public class AllowSnakeCaseFilterTest extends BaseInterpretingTest {
10+
11+
@Test
12+
public void itDoesNotChangeNonMaps() {
13+
assertThat(interpreter.render("{{ 'fooBar'|allow_snake_case }}")).isEqualTo("fooBar");
14+
}
15+
16+
@Test
17+
public void itMakesMapKeysAccessibleWithSnakeCase() {
18+
assertThat(interpreter.render("{{ ({'fooBar': 'foo'}|allow_snake_case).foo_bar }}"))
19+
.isEqualTo("foo");
20+
}
21+
22+
@Test
23+
public void itReserializesAsSnakeCaseAccessibleMap() {
24+
interpreter.render("{% set map = {'fooBar': 'foo'}|allow_snake_case %}");
25+
assertThat(PyishObjectMapper.getAsPyishString(interpreter.getContext().get("map")))
26+
.isEqualTo("{'fooBar': 'foo'} |allow_snake_case");
27+
}
28+
}

0 commit comments

Comments
 (0)