Skip to content

Commit 383e9c2

Browse files
committed
Unparse a mustache template and output into a Scope
1 parent fbbe8c0 commit 383e9c2

File tree

11 files changed

+450
-9
lines changed

11 files changed

+450
-9
lines changed

builder/src/main/java/com/sampullara/mustache/MustacheBuilder.java

Lines changed: 187 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,17 @@
1313
import java.io.InputStreamReader;
1414
import java.io.Reader;
1515
import java.io.StringReader;
16+
import java.io.StringWriter;
1617
import java.util.ArrayList;
18+
import java.util.HashMap;
1719
import java.util.LinkedList;
1820
import java.util.List;
21+
import java.util.Map;
1922
import java.util.concurrent.Callable;
2023
import java.util.concurrent.atomic.AtomicInteger;
2124

25+
import static com.sampullara.mustache.Mustache.truncate;
26+
2227
/**
2328
* A pseudo interpreter / compiler. Instead of compiling to Java code, it compiles to a
2429
* list of instructions to execute.
@@ -81,7 +86,7 @@ public Mustache parseFile(String path) throws MustacheException {
8186
if (root == null) {
8287
String fullPath = classpathRoot == null ? path : classpathRoot + "/" + path;
8388
InputStream resourceAsStream =
84-
MustacheBuilder.class.getClassLoader().getResourceAsStream(fullPath);
89+
MustacheBuilder.class.getClassLoader().getResourceAsStream(fullPath);
8590
if (resourceAsStream == null) {
8691
throw new MustacheException(path + " not found in classpath");
8792
}
@@ -184,7 +189,7 @@ protected List<Code> compile(final Mustache m, final Reader br, String tag, fina
184189
}
185190
if (!variable.equals(tag)) {
186191
throw new MustacheException(
187-
"Mismatched start/end tags: " + tag + " != " + variable + " in " + file + ":" + currentLine);
192+
"Mismatched start/end tags: " + tag + " != " + variable + " in " + file + ":" + currentLine);
188193
}
189194

190195
return list;
@@ -203,7 +208,7 @@ protected List<Code> compile(final Mustache m, final Reader br, String tag, fina
203208
} else {
204209
if (br.read() != '}') {
205210
throw new MustacheException(
206-
"Improperly closed variable in " + file + ":" + currentLine);
211+
"Improperly closed variable in " + file + ":" + currentLine);
207212
}
208213
}
209214
final String finalName = name;
@@ -268,7 +273,7 @@ private StringBuilder write(List<Code> list, StringBuilder out, int line) {
268273
private abstract static class SubCode implements Code {
269274
protected final Mustache m;
270275
protected final String variable;
271-
private final Code[] codes;
276+
protected final Code[] codes;
272277
private final int line;
273278
private final String file;
274279

@@ -325,6 +330,30 @@ public IterableCode(Mustache m, String variable, List<Code> codes, String file,
325330
public void execute(FutureWriter fw, Scope scope) throws MustacheException {
326331
execute(fw, m.iterable(scope, variable));
327332
}
333+
334+
@Override
335+
public Scope unparse(Scope current, String text, AtomicInteger position, Code[] next) throws MustacheException {
336+
// I think we have to make iteration greedy and match until we can't find a match
337+
List<Scope> results = new ArrayList<Scope>();
338+
Scope result;
339+
do {
340+
result = new Scope();
341+
for (int i = 0; i < codes.length && result != null; i++) {
342+
if (Mustache.debug) {
343+
Mustache.line.set(codes[i].getLine());
344+
}
345+
Code[] truncate = truncate(codes, i + 1);
346+
result = codes[i].unparse(result, text, position, truncate);
347+
}
348+
if (result != null && result.size() > 0) {
349+
results.add(result);
350+
} else break;
351+
} while (true);
352+
if (results.size() != 0) {
353+
current.put(variable, results);
354+
}
355+
return current;
356+
}
328357
}
329358

330359
private static class FunctionCode extends SubCode {
@@ -343,6 +372,46 @@ public void execute(FutureWriter fw, Scope scope) throws MustacheException {
343372
throw new MustacheException("Not a function: " + function);
344373
}
345374
}
375+
376+
static class MapFunction implements Function<String, String> {
377+
private Map<String, String> map = new HashMap<String, String>();
378+
379+
void put(String input, String value) {
380+
map.put(input, value);
381+
}
382+
383+
@Override
384+
public String apply(String input) {
385+
return map.get(input);
386+
}
387+
388+
public String toString() {
389+
return map.toString();
390+
}
391+
}
392+
393+
@Override
394+
public Scope unparse(Scope current, final String text, final AtomicInteger position, Code[] next) throws MustacheException {
395+
final String value = unparseValueCode(current, text, position, next, false);
396+
if (value == null) return null;
397+
MapFunction function = (FunctionCode.MapFunction) current.get(variable);
398+
if (function == null) {
399+
function = new MapFunction();
400+
put(current, variable, function);
401+
}
402+
StringWriter sw = new StringWriter();
403+
FutureWriter fw = new FutureWriter(sw);
404+
try {
405+
for (Code code : codes) {
406+
code.execute(fw, current);
407+
}
408+
fw.flush();
409+
} catch (IOException e) {
410+
throw new MustacheException("Failed to evaluate function body", e);
411+
}
412+
function.put(sw.toString(), value);
413+
return current;
414+
}
346415
}
347416

348417
private static class IfIterableCode extends SubCode {
@@ -358,6 +427,23 @@ public void execute(FutureWriter fw, Scope scope) throws MustacheException {
358427
}
359428
execute(fw, m.ifiterable(scope, variable));
360429
}
430+
431+
@Override
432+
public Scope unparse(Scope current, String text, AtomicInteger position, Code[] next) throws MustacheException {
433+
// Like the iterable version with only one
434+
Scope result = new Scope();
435+
for (int i = 0; i < codes.length && result != null; i++) {
436+
if (Mustache.debug) {
437+
Mustache.line.set(codes[i].getLine());
438+
}
439+
Code[] truncate = truncate(codes, i + 1);
440+
result = codes[i].unparse(result, text, position, truncate);
441+
}
442+
if (result != null && result.size() > 0) {
443+
put(current, variable, result);
444+
}
445+
return current;
446+
}
361447
}
362448

363449
private static class InvertedIterableCode extends SubCode {
@@ -373,6 +459,24 @@ public void execute(FutureWriter fw, Scope scope) throws MustacheException {
373459
}
374460
execute(fw, m.inverted(scope, variable));
375461
}
462+
463+
@Override
464+
public Scope unparse(Scope current, String text, AtomicInteger position, Code[] next) throws MustacheException {
465+
// Like the iterable version with only one
466+
Scope result = new Scope();
467+
for (int i = 0; i < codes.length && result != null; i++) {
468+
if (Mustache.debug) {
469+
Mustache.line.set(codes[i].getLine());
470+
}
471+
Code[] truncate = truncate(codes, i + 1);
472+
result = codes[i].unparse(result, text, position, truncate);
473+
}
474+
if (result != null) {
475+
current.putAll(result);
476+
put(current, variable, false);
477+
}
478+
return current;
479+
}
376480
}
377481

378482
private static class PartialCode implements Code {
@@ -409,6 +513,14 @@ public Object call() throws Exception {
409513
public int getLine() {
410514
return line;
411515
}
516+
517+
@Override
518+
public Scope unparse(Scope current, String text, AtomicInteger position, Code[] next) throws MustacheException {
519+
Scope unparse = m.partial(variable).unparse(text, position);
520+
if (unparse == null) return null;
521+
put(current, variable, unparse);
522+
return current;
523+
}
412524
}
413525

414526
private static class WriteValueCode implements Code {
@@ -433,6 +545,59 @@ public void execute(FutureWriter fw, Scope scope) throws MustacheException {
433545
public int getLine() {
434546
return line;
435547
}
548+
549+
@Override
550+
public Scope unparse(Scope current, String text, AtomicInteger position, Code[] next) throws MustacheException {
551+
String value = unparseValueCode(current, text, position, next, encoded);
552+
if (value != null) {
553+
put(current, name, value);
554+
return current;
555+
}
556+
return null;
557+
}
558+
559+
}
560+
561+
private static String unparseValueCode(Scope current, String text, AtomicInteger position, Code[] next, boolean encoded) throws MustacheException {
562+
AtomicInteger probePosition = new AtomicInteger(position.get());
563+
Code[] truncate = truncate(next, 1);
564+
Scope result = null;
565+
int lastposition = position.get();
566+
while (next.length != 0 && probePosition.get() < text.length()) {
567+
lastposition = probePosition.get();
568+
result = next[0].unparse(current, text, probePosition, truncate);
569+
if (result == null) {
570+
probePosition.incrementAndGet();
571+
} else {
572+
break;
573+
}
574+
}
575+
if (result != null) {
576+
String value = text.substring(position.get(), lastposition);
577+
if (encoded) {
578+
// Decode
579+
}
580+
position.set(lastposition);
581+
return value;
582+
}
583+
return null;
584+
}
585+
586+
private static void put(Scope result, String name, Object value) {
587+
String[] splits = name.split("[.]");
588+
Scope depth = result;
589+
for (int i = 0; i < splits.length; i++) {
590+
if (i < splits.length - 1) {
591+
Scope tmp = (Scope) result.get(splits[i]);
592+
if (tmp == null) {
593+
tmp = new Scope();
594+
}
595+
depth.put(splits[i], tmp);
596+
depth = tmp;
597+
} else {
598+
depth.put(splits[i], value);
599+
}
600+
}
436601
}
437602

438603
private static class WriteCode implements Code {
@@ -457,9 +622,27 @@ public int getLine() {
457622
return line;
458623
}
459624

625+
<<<<<<< HEAD
626+
@Override
627+
public Scope unparse(Scope current, String text, AtomicInteger position, Code[] next) throws MustacheException {
628+
if (position.get() + rest.length() <= text.length()) {
629+
String substring = text.substring(position.get(), position.get() + rest.length());
630+
if (rest.toString().equals(substring)) {
631+
position.addAndGet(rest.length());
632+
return current;
633+
}
634+
}
635+
return null;
636+
}
637+
638+
public void append(String append) {
639+
rest.append(append);
640+
}
641+
=======
460642
public void append(String append) {
461643
rest.append(append);
462644
}
463645

646+
>>>>>>> master
464647
}
465648
}

0 commit comments

Comments
 (0)