diff --git a/src/main/java/com/samskivert/mustache/Template.java b/src/main/java/com/samskivert/mustache/Template.java index 1ae3c66..19907e9 100644 --- a/src/main/java/com/samskivert/mustache/Template.java +++ b/src/main/java/com/samskivert/mustache/Template.java @@ -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); @@ -107,14 +113,15 @@ public class Template 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); diff --git a/src/test/java/com/samskivert/mustache/MustacheTest.java b/src/test/java/com/samskivert/mustache/MustacheTest.java index e0f9e2d..02b9bf3 100644 --- a/src/test/java/com/samskivert/mustache/MustacheTest.java +++ b/src/test/java/com/samskivert/mustache/MustacheTest.java @@ -665,16 +665,41 @@ public class MustacheTest } @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 () {