diff --git a/src/main/java/com/samskivert/mustache/BasicCollector.java b/src/main/java/com/samskivert/mustache/BasicCollector.java index f9278c1..bd324c2 100644 --- a/src/main/java/com/samskivert/mustache/BasicCollector.java +++ b/src/main/java/com/samskivert/mustache/BasicCollector.java @@ -6,6 +6,7 @@ package com.samskivert.mustache; import java.util.Collections; import java.util.Iterator; +import java.util.List; import java.util.Map; /** @@ -25,12 +26,16 @@ public abstract class BasicCollector implements Mustache.Collector public Mustache.VariableFetcher createFetcher (Object ctx, String name) { // support both .name and this.name to fetch members - if (name == Template.DOT_NAME || name == Template.THIS_NAME) { - return THIS_FETCHER; - } + if (name == Template.DOT_NAME || name == Template.THIS_NAME) return THIS_FETCHER; - if (ctx instanceof Map) { - return MAP_FETCHER; + if (ctx instanceof Map) return MAP_FETCHER; + + // if the name looks like a number, potentially use one of our 'indexing' fetchers + char c = name.charAt(0); + if (c >= '0' && c <= '9') { + if (ctx instanceof List) return LIST_FETCHER; + if (ctx instanceof Object[]) return ARRAY_FETCHER; + if (ctx instanceof Iterator) return ITER_FETCHER; } return null; @@ -47,6 +52,38 @@ public abstract class BasicCollector implements Mustache.Collector } }; + protected static final Mustache.VariableFetcher LIST_FETCHER = new Mustache.VariableFetcher() { + public Object get (Object ctx, String name) throws Exception { + try { + return ((List)ctx).get(Integer.parseInt(name)); + } catch (NumberFormatException nfe) { + return Template.NO_FETCHER_FOUND; + } + } + }; + + protected static final Mustache.VariableFetcher ARRAY_FETCHER = new Mustache.VariableFetcher() { + public Object get (Object ctx, String name) throws Exception { + try { + return ((Object[])ctx)[Integer.parseInt(name)]; + } catch (NumberFormatException nfe) { + return Template.NO_FETCHER_FOUND; + } + } + }; + + protected static final Mustache.VariableFetcher ITER_FETCHER = new Mustache.VariableFetcher() { + public Object get (Object ctx, String name) throws Exception { + try { + Iterator iter = (Iterator)ctx; + for (int ii = 0, ll = Integer.parseInt(name); ii < ll; ii++) iter.next(); + return iter.next(); + } catch (NumberFormatException nfe) { + return Template.NO_FETCHER_FOUND; + } + } + }; + protected static final Mustache.VariableFetcher THIS_FETCHER = new Mustache.VariableFetcher() { public Object get (Object ctx, String name) throws Exception { return ctx; diff --git a/src/main/java/com/samskivert/mustache/Template.java b/src/main/java/com/samskivert/mustache/Template.java index 2261ecd..c45aeb2 100644 --- a/src/main/java/com/samskivert/mustache/Template.java +++ b/src/main/java/com/samskivert/mustache/Template.java @@ -7,12 +7,8 @@ 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; /** @@ -143,18 +139,7 @@ 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 - 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); - } + data = getValueIn(data, comps[ii].intern(), line); } return checkForMissing(name, line, missingIsNull, data); } @@ -184,30 +169,6 @@ 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