Home | History | Annotate | Download | only in mustache
      1 package org.testng.mustache;
      2 
      3 import org.testng.collections.Lists;
      4 
      5 import java.io.IOException;
      6 import java.util.List;
      7 import java.util.Map;
      8 
      9 public class Mustache {
     10 
     11   public String run(String template, Map<String, Object> m) throws IOException {
     12     return run(template, new Model(m));
     13   }
     14 
     15   String run(String template, Model model) throws IOException {
     16     int lineNumber = 0;
     17 
     18     List<BaseChunk> chunks = Lists.newArrayList();
     19     int ti = 0;
     20     while (ti < template.length()) {
     21       int start;
     22       int end;
     23       if (template.charAt(ti) == '\n') lineNumber++;
     24 
     25       if (template.charAt(ti) == '{' && ti + 1 < template.length()
     26           && template.charAt(ti + 1) == '{') {
     27         int index = ti + 2;
     28         start = index;
     29         boolean foundEnd = false;
     30         while (index < template.length() && ! foundEnd) {
     31           index++;
     32           foundEnd = template.charAt(index) == '}' && index + 1 < template.length()
     33               && template.charAt(index + 1) == '}';
     34         }
     35 
     36         if (foundEnd) {
     37           end = index;
     38           String variable = template.substring(start, end);
     39           p("Found variable:" + variable);
     40           if (variable.startsWith("#")) {
     41             // Complex variable {{#foo}}.
     42             String conditionalVariable = variable.substring(1);
     43             Value value = model.resolveValue(conditionalVariable);
     44             int endIndex = findClosingIndex(template, ti, conditionalVariable);
     45             Object v = value.get();
     46             if (v == null) {
     47               // Null condition, do nothing
     48             } else if (v instanceof Iterable) {
     49               // Iterable, call a sub Mustache to process this chunk in a loop
     50               // after pushing a new submodel
     51               Iterable it = (Iterable) v;
     52               String subTemplate = template.substring(ti + variable.length() + 4, endIndex);
     53               for (Object o : it) {
     54                 model.push(conditionalVariable, o);
     55                 String r = new Mustache().run(subTemplate, model);
     56                 model.popSubModel();
     57                 chunks.add(new StringChunk(model, r));
     58               }
     59             } else {
     60               // Scope, call a sub Mustache to process this chunk
     61               // after pushing a new submodel
     62               String subTemplate = template.substring(ti + variable.length() + 4, endIndex);
     63               model.push(conditionalVariable, v);
     64               String r = new Mustache().run(subTemplate, model);
     65               model.popSubModel();
     66               chunks.add(new StringChunk(model, r));
     67             }
     68             ti = endIndex + variable.length() + 4;
     69           } else {
     70             // Regular variable {{foo}}
     71             chunks.add(new VariableChunk(model, variable));
     72             ti += variable.length() + 4;
     73           }
     74         } else {
     75           throw new RuntimeException("Unclosed variable at line " + lineNumber);
     76         }
     77       } else {
     78         chunks.add(new StringChunk(model, "" + template.charAt(ti)));
     79         ti++;
     80       }
     81     } // while
     82 
     83     p("******************** Final composition, chunks:");
     84     StringBuilder result = new StringBuilder();
     85     p("*** Template:" + template);
     86     for (BaseChunk bc : chunks) {
     87       p("***  " + bc);
     88     }
     89 
     90     for (BaseChunk bc : chunks) {
     91       String c = bc.compose();
     92       result.append(c);
     93     }
     94     p("*** Final result:" + result);
     95     return result.toString();
     96   }
     97 
     98   private int findClosingIndex(String template, int ti,
     99       String conditionalVariable) {
    100     int result = template.lastIndexOf("{{/" + conditionalVariable);
    101     return result;
    102   }
    103 
    104   private void p(String string) {
    105     if (false) {
    106       System.out.println(string);
    107     }
    108   }
    109 
    110   public static void main(String[] args) throws IOException {
    111   }
    112 }
    113