Skip to content

Commit

Permalink
Expose the context to a lambda fragment.
Browse files Browse the repository at this point in the history
This allows the lambda to take the context and turn around and render it using
a totally different template, if desired.
  • Loading branch information
samskivert committed Apr 16, 2014
1 parent 5bb76b0 commit 20abde5
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 12 deletions.
11 changes: 9 additions & 2 deletions src/main/java/com/samskivert/mustache/Template.java
Expand Up @@ -40,6 +40,12 @@ public class Template
* the variable context that was in effect at the time the lambda was called.
*/
public abstract class Fragment {
/** Returns the context object in effect for this fragment. The actual type of the object
* depends on the structure of the data passed to the top-level template. You know where
* your lambdas are executed, so you know what type to which to cast the context in order
* to inspect it (be that a {@code Map} or a POJO or something else). */
public abstract Object context ();

/** Executes this fragment; writes its result to {@code out}. */
public abstract void execute (Writer out);

Expand Down Expand Up @@ -107,14 +113,15 @@ protected void executeSegs (Context ctx, Writer out) throws MustacheException {

protected Fragment createFragment (final Segment[] segs, final Context currentCtx) {
return new Fragment() {
@Override public Object context () {
return currentCtx.data;
}
@Override public void execute (Writer out) {
execute(currentCtx, out);
}

@Override public void execute (Object context, Writer out) {
execute(currentCtx.nest(context, 0, false, false), out);
}

private void execute (Context ctx, Writer out) {
for (Segment seg : segs) {
seg.execute(Template.this, ctx, out);
Expand Down
45 changes: 35 additions & 10 deletions src/test/java/com/samskivert/mustache/MustacheTest.java
Expand Up @@ -665,16 +665,41 @@ public void execute (Template.Fragment frag, Writer out) throws IOException {
}

@Test public void testLambdaWithContext () {
test("a in l1, a in l2", "{{#l1}}{{a}}{{/l1}}, {{#l2}}{{a}}{{/l2}}",
context("l1", new Mustache.Lambda() {
public void execute (Template.Fragment frag, Writer out) throws IOException {
frag.execute(context("a", "a in l1"), out);
}
}, "l2", new Mustache.Lambda() {
public void execute (Template.Fragment frag, Writer out) throws IOException {
frag.execute(context("a", "a in l2"), out);
}
}));
test("a in l1, a in l2", "{{#l1}}{{a}}{{/l1}}, {{#l2}}{{a}}{{/l2}}", context(
"l1", new Mustache.Lambda() {
public void execute (Template.Fragment frag, Writer out) throws IOException {
frag.execute(context("a", "a in l1"), out);
}
},
"l2", new Mustache.Lambda() {
public void execute (Template.Fragment frag, Writer out) throws IOException {
frag.execute(context("a", "a in l2"), out);
}
}));
}

@Test public void testContextPokingLambda () {
Mustache.Compiler c = Mustache.compiler();

class Foo { public int foo = 1; }
final Template lfoo = c.compile("{{foo}}");
assertEquals("1", lfoo.execute(new Foo()));

class Bar { public String bar = "one"; }
final Template lbar = c.compile("{{bar}}");
assertEquals("one", lbar.execute(new Bar()));

test(c, "1oneone1one!", "{{#events}}{{#renderEvent}}{{/renderEvent}}{{/events}}", context(
"renderEvent", new Mustache.Lambda() {
public void execute (Template.Fragment frag, Writer out) throws IOException {
Object ctx = frag.context();
if (ctx instanceof Foo) lfoo.execute(ctx, out);
else if (ctx instanceof Bar) lbar.execute(ctx, out);
else out.write("!");
}
},
"events", Arrays.asList(
new Foo(), new Bar(), new Bar(), new Foo(), new Bar(), "wtf?")));
}

@Test public void testNonStandardDefaultDelims () {
Expand Down

0 comments on commit 20abde5

Please sign in to comment.