diff --git a/compiler/src/main/java/com/github/mustachejava/DefaultMustacheVisitor.java b/compiler/src/main/java/com/github/mustachejava/DefaultMustacheVisitor.java index 5998fceb0..6a233eaf0 100644 --- a/compiler/src/main/java/com/github/mustachejava/DefaultMustacheVisitor.java +++ b/compiler/src/main/java/com/github/mustachejava/DefaultMustacheVisitor.java @@ -7,6 +7,7 @@ import com.github.mustachejava.codes.IterableCode; import com.github.mustachejava.codes.NotIterableCode; import com.github.mustachejava.codes.PartialCode; +import com.github.mustachejava.codes.DynamicPartialCode; import com.github.mustachejava.codes.ValueCode; import com.github.mustachejava.codes.WriteCode; import com.github.mustachejava.util.Node; @@ -82,6 +83,12 @@ public void partial(TemplateContext tc, final String variable) { TemplateContext partialTC = new TemplateContext("{{", "}}", tc.file(), tc.line(), tc.startOfLine()); list.add(new PartialCode(partialTC, df, variable)); } + + @Override + public void dynamicPartial(TemplateContext tc, final String variable) { + TemplateContext partialTC = new TemplateContext("{{", "}}", tc.file(), tc.line(), tc.startOfLine()); + list.add(new DynamicPartialCode(partialTC, df, variable)); + } @Override public void value(TemplateContext tc, final String variable, boolean encoded) { diff --git a/compiler/src/main/java/com/github/mustachejava/MustacheParser.java b/compiler/src/main/java/com/github/mustachejava/MustacheParser.java index de1802e67..a62f7357d 100644 --- a/compiler/src/main/java/com/github/mustachejava/MustacheParser.java +++ b/compiler/src/main/java/com/github/mustachejava/MustacheParser.java @@ -215,6 +215,11 @@ protected Mustache compile(final Reader reader, String tag, final AtomicInteger sm = delimiters.substring(1, length / 2); em = delimiters.substring(length / 2, length - 1); break; + case '+': + out = write(mv, out, file, currentLine.intValue(), startOfLine); + startOfLine = startOfLine & onlywhitespace; + mv.dynamicPartial(new TemplateContext(sm, em, file, currentLine.get(), startOfLine), variable); + break; default: { if (c == -1) { throw new MustacheException( diff --git a/compiler/src/main/java/com/github/mustachejava/MustacheVisitor.java b/compiler/src/main/java/com/github/mustachejava/MustacheVisitor.java index ea2535872..6acb0f12d 100644 --- a/compiler/src/main/java/com/github/mustachejava/MustacheVisitor.java +++ b/compiler/src/main/java/com/github/mustachejava/MustacheVisitor.java @@ -27,5 +27,8 @@ public interface MustacheVisitor { void extend(TemplateContext templateContext, String variable, Mustache mustache); void name(TemplateContext templateContext, String variable, Mustache mustache); + + void dynamicPartial(TemplateContext paramTemplateContext, + String paramString); } diff --git a/compiler/src/main/java/com/github/mustachejava/codes/DynamicPartialCode.java b/compiler/src/main/java/com/github/mustachejava/codes/DynamicPartialCode.java new file mode 100644 index 000000000..390657790 --- /dev/null +++ b/compiler/src/main/java/com/github/mustachejava/codes/DynamicPartialCode.java @@ -0,0 +1,91 @@ +package com.github.mustachejava.codes; + +import com.github.mustachejava.*; + +import java.io.IOException; +import java.io.Writer; + +public class DynamicPartialCode extends DefaultCode { + protected final String extension; + protected final String dir; + protected Mustache partial; + protected int recrusionLimit; + + protected DynamicPartialCode(TemplateContext tc, DefaultMustacheFactory df, Mustache mustache, String type, String variable) { + super(tc, df, mustache, variable, type); + // Use the name of the parent to get the name of the partial + String file = tc.file(); + int dotindex = file.lastIndexOf("."); + extension = dotindex == -1 ? "" : file.substring(dotindex); + int slashindex = file.lastIndexOf("/"); + dir = file.substring(0, slashindex + 1); + recrusionLimit = df.getRecursionLimit(); + } + + public DynamicPartialCode(TemplateContext tc, DefaultMustacheFactory cf, String variable) { + this(tc, cf, null, ">", variable); + } + + @Override + public void identity(Writer writer) { + try { + if (name != null) { + super.tag(writer, type); + } + appendText(writer); + } catch (IOException e) { + throw new MustacheException(e); + } + } + + @Override + public Code[] getCodes() { + return partial == null ? null : partial.getCodes(); + } + + @Override + public void setCodes(Code[] newcodes) { + partial.setCodes(newcodes); + } + + @Override + public Writer execute(Writer writer, final Object[] scopes) { + DepthLimitedWriter depthLimitedWriter; + if (writer instanceof DepthLimitedWriter) { + depthLimitedWriter = (DepthLimitedWriter) writer; + } else { + depthLimitedWriter = new DepthLimitedWriter(writer); + } + if (depthLimitedWriter.incr() > recrusionLimit) { + throw new MustacheException("Maximum partial recursion limit reached: " + recrusionLimit); + } + try{ + if(get(scopes)!=null) + partial = df.compilePartial(get(scopes) +".html"); + }catch(Exception e){ + throw new MustacheException("Failed to compile partial: " + name); + } + if (partial == null) { + throw new MustacheException("Failed to compile partial: " + name); + } + Writer execute = partial.execute(depthLimitedWriter, scopes); + depthLimitedWriter.decr(); + return appendText(execute); + } + + @Override + public synchronized void init() { + filterText(); + } + + /** + * Builds the file name to be included by this partial tag. Default implementation ppends the tag contents with + * the current file's extension. + * + * @return The filename to be included by this partial tag + */ + protected String partialName() { + return df.resolvePartialPath(dir, name, extension); + } + +} diff --git a/compiler/src/test/java/com/github/mustachejava/DyanmicPartialTest.java b/compiler/src/test/java/com/github/mustachejava/DyanmicPartialTest.java new file mode 100644 index 000000000..0b5de1788 --- /dev/null +++ b/compiler/src/test/java/com/github/mustachejava/DyanmicPartialTest.java @@ -0,0 +1,26 @@ +package com.github.mustachejava; + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.Map; + +import org.junit.Test; + +public class DyanmicPartialTest { + static Map obj = new HashMap(); + + @Test + public void testAbstractClass() throws IOException { + + obj.put("firstName", "Check"); + obj.put("lastName", "Mate"); + obj.put("blogURL", "is something"); + obj.put("parent", "partial"); + + PrintWriter pw = new PrintWriter(System.out); + MustacheFactory mustachefactory = new DefaultMustacheFactory(); + Mustache mustacheTemplate = mustachefactory.compile("index.html"); + mustacheTemplate.execute(pw, obj).close(); + } +} diff --git a/compiler/src/test/resources/index.html b/compiler/src/test/resources/index.html new file mode 100644 index 000000000..f7d27907a --- /dev/null +++ b/compiler/src/test/resources/index.html @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/compiler/src/test/resources/parent.html b/compiler/src/test/resources/parent.html new file mode 100644 index 000000000..e9619b0a3 --- /dev/null +++ b/compiler/src/test/resources/parent.html @@ -0,0 +1 @@ +

Parent is: {{blogURL}}

\ No newline at end of file diff --git a/compiler/src/test/resources/partial.html b/compiler/src/test/resources/partial.html new file mode 100644 index 000000000..0d5428d35 --- /dev/null +++ b/compiler/src/test/resources/partial.html @@ -0,0 +1,2 @@ +

Dynamic Partial is: {{blogURL}}

+