From 98c7a5d38fc98a72dfbd798e17ac5a537552fb1c Mon Sep 17 00:00:00 2001 From: Mickael Jeanroy Date: Sat, 5 Oct 2013 22:26:14 +0200 Subject: [PATCH] Access Array item by index in template --- .../com/samskivert/mustache/Template.java | 41 ++++++++++++++++++- .../com/samskivert/mustache/MustacheTest.java | 34 +++++++++++++++ 2 files changed, 74 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/samskivert/mustache/Template.java b/src/main/java/com/samskivert/mustache/Template.java index c45aeb2..2261ecd 100644 --- a/src/main/java/com/samskivert/mustache/Template.java +++ b/src/main/java/com/samskivert/mustache/Template.java @@ -7,8 +7,12 @@ package com.samskivert.mustache; import java.io.IOException; import java.io.StringWriter; import java.io.Writer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.Iterator; +import java.util.List; import java.util.Map; /** @@ -139,7 +143,18 @@ public class Template } // once we step into a composite key, we drop the ability to query our parent // contexts; that would be weird and confusing - data = getValueIn(data, comps[ii].intern(), line); + String next = comps[ii].intern(); + Integer idx = toNumber(next); + if (idx != null) { + Object nextData = null; + List c = toList(data); + if (c != null && idx >= 0 && idx < c.size()) { + nextData = c.get(idx); + } + data = nextData; + } else { + data = getValueIn(data, next, line); + } } return checkForMissing(name, line, missingIsNull, data); } @@ -169,6 +184,30 @@ public class Template return checkForMissing(name, line, missingIsNull, NO_FETCHER_FOUND); } + protected static List toList(Object obj) { + if (obj instanceof Collection) { + return new ArrayList((Collection) obj); + } else if (obj instanceof Iterator) { + Iterator it = (Iterator) obj; + List lst = new ArrayList(); + while (it.hasNext()) { + lst.add(it.next()); + } + return lst; + } else if (obj instanceof Object[]) { + return Arrays.asList((Object[]) obj); + } + return null; + } + + protected static Integer toNumber(String value) { + try { + return Integer.parseInt(value); + } catch (NumberFormatException ex) { + return null; + } + } + /** * Returns the value of the specified variable, noting that it is intended to be used as the * contents for a segment. Presently this does not do anything special, but eventually this diff --git a/src/test/java/com/samskivert/mustache/MustacheTest.java b/src/test/java/com/samskivert/mustache/MustacheTest.java index eacb06c..9b5043a 100644 --- a/src/test/java/com/samskivert/mustache/MustacheTest.java +++ b/src/test/java/com/samskivert/mustache/MustacheTest.java @@ -87,18 +87,52 @@ public class MustacheTest "foo", Arrays.asList(context("bar", "baz"), context("bar", "bif")))); } + @Test public void testListIndexSection() { + test("baz", "{{#foo.0}}{{bar}}{{/foo.0}}", context( + "foo", Arrays.asList(context("bar", "baz"), context("bar", "bif")))); + } + + @Test public void testListItemSection() { + test("baz", "{{foo.0.bar}}", context( + "foo", Arrays.asList(context("bar", "baz"), context("bar", "bif")))); + } + @Test public void testArraySection () { test("bazbif", "{{#foo}}{{bar}}{{/foo}}", context("foo", new Object[] { context("bar", "baz"), context("bar", "bif") })); } + @Test public void testArrayIndexSection () { + test("baz", "{{#foo.0}}{{bar}}{{/foo.0}}", + context("foo", new Object[] { + context("bar", "baz"), context("bar", "bif") })); + } + + @Test public void testArrayItemSection () { + test("baz", "{{foo.0.bar}}", + context("foo", new Object[] { + context("bar", "baz"), context("bar", "bif") })); + } + @Test public void testIteratorSection () { test("bazbif", "{{#foo}}{{bar}}{{/foo}}", context("foo", Arrays.asList(context("bar", "baz"), context("bar", "bif")).iterator())); } + @Test public void testIteratorIndexSection () { + test("baz", "{{#foo.0}}{{bar}}{{/foo.0}}", + context("foo", Arrays.asList(context("bar", "baz"), + context("bar", "bif")).iterator())); + } + + @Test public void testIteratorItemSection () { + test("baz", "{{foo.0.bar}}", + context("foo", Arrays.asList(context("bar", "baz"), + context("bar", "bif")).iterator())); + } + @Test public void testEmptyListSection () { test("", "{{#foo}}{{bar}}{{/foo}}", context("foo", Collections.emptyList())); }