Advertisement
Guest User

Templatron

a guest
Mar 31st, 2015
253
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 6.79 KB | None | 0 0
  1. import java.io.File;
  2. import java.io.FileReader;
  3. import java.io.IOException;
  4. import java.io.InputStreamReader;
  5. import java.io.Writer;
  6. import java.net.URL;
  7. import java.util.ArrayList;
  8. import java.util.List;
  9. import java.util.Map;
  10.  
  11. /**
  12.  * 'Templatron' template library. Quick Example Usage:
  13. <pre>Template template = Templatron.newTemplate("Hello, %{name=NULL}! How are you? I am %{feel}.");
  14.  
  15. HashMap<String, String> valueMap = new HashMap<>();
  16. valueMap.put("name", "Coder");
  17. valueMap.put("feel", "fine");
  18.  
  19. Templatron.render(template, valueMap, new PrintWriter(System.out));
  20.  * </pre>
  21.  * FOR THE SAKE OF SANITY: Do NOT use this library in production! This code was written to just work, without giving a f**k about anything.
  22.  **/
  23. public class Templatron {
  24.     /**
  25.      * Creates a new template from a string.
  26.      * @param source The string to parse.
  27.      * @return A new template, generated from the given string.
  28.      **/
  29.     public static final Template newTemplate(String source) {
  30.         if(source == null)
  31.             throw new NullPointerException("'source' cannot be null!");
  32.        
  33.         Template template = new Template();
  34.         template.load(source);
  35.         return template;
  36.     }
  37.    
  38.     /**
  39.      * Creates a new template from a string.
  40.      * @param file The file to parse.
  41.      * @return A new template, generated from the given string.
  42.      * @throws IOException If the file could not be opened/read.
  43.      **/
  44.     public static final Template newTemplate(File file) throws IOException {
  45.         if(file == null)
  46.             throw new NullPointerException("'file' cannot be null!");
  47.        
  48.         StringBuilder bd = new StringBuilder();
  49.         FileReader read = new FileReader(file);
  50.         {
  51.             int i = 0;
  52.             while((i = read.read()) != -1)
  53.                 bd.append((char)i);
  54.         }
  55.         read.close();
  56.        
  57.         Template template = new Template();
  58.         template.load(bd.toString());
  59.         return template;
  60.     }
  61.    
  62.     /**
  63.      * Creates a new template from a string.
  64.      * @param url The url to parse.
  65.      * @return A new template, generated from the given string.
  66.      * @throws IOException If the url could not be opened/read.
  67.      **/
  68.     public static final Template newTemplate(URL url) throws IOException {
  69.         if(url == null)
  70.             throw new NullPointerException("'url' cannot be null!");
  71.        
  72.         StringBuilder bd = new StringBuilder();
  73.         InputStreamReader read = new InputStreamReader(url.openStream());
  74.         {
  75.             int i = 0;
  76.             while((i = read.read()) != -1)
  77.                 bd.append((char)i);
  78.         }
  79.         read.close();
  80.        
  81.         Template template = new Template();
  82.         template.load(bd.toString());
  83.         return template;
  84.     }
  85.    
  86.     /**
  87.      * Instances of this class parse and store a template.
  88.      **/
  89.     public static class Template {
  90.         List<Piece> pieces;
  91.        
  92.         protected Template() {
  93.             pieces = new ArrayList<>();
  94.         }
  95.        
  96.         @Override
  97.         public String toString() {
  98.             return "Template:{pieces.size="+pieces.size()+"}";
  99.         }
  100.        
  101.         /**
  102.          * This is were the magic happens!
  103.          * @param source The string to parse.
  104.          **/
  105.         public void load(String source) {
  106.             StringBuilder buffer = new StringBuilder(source.length());
  107.            
  108.             for(int CHARINDEX = 0; CHARINDEX < source.length(); CHARINDEX++) {
  109.                 char CHAR = source.charAt(CHARINDEX);
  110.                
  111.                 // IF %{ ... }
  112.                 if(CHAR == '%' && peek(source, CHARINDEX+1, ' ') == '{') {
  113.                     int start = CHARINDEX+2;
  114.                     int end = findNext(source, CHARINDEX+1, '}');
  115.                    
  116.                     if(end == -1) {
  117.                         buffer.append(CHAR);
  118.                         continue;
  119.                     }
  120.                    
  121.                     {
  122.                         // Flush buffer!
  123.                         String str = buffer.toString();
  124.                         buffer.setLength(0);
  125.                         TextPiece tp = new TextPiece();
  126.                         tp.data = str;
  127.                         pieces.add(tp);
  128.                     }
  129.                    
  130.                     // Cut it out.
  131.                     String link = source.substring(start, end);
  132.                    
  133.                     // Do your thing!
  134.                     LinkPiece tp = new LinkPiece();
  135.                     pieces.add(tp);
  136.                    
  137.                     // Has 'default' value embedded?
  138.                     if(link.indexOf('=') != -1) {
  139.                         // Yes, so extract it!
  140.                         int i = link.indexOf('=');
  141.                         String k = link.substring(0, i);
  142.                         String d = link.substring(i+1);
  143.                         tp.data = k;
  144.                         tp.defaultdata = d;
  145.                     } else {
  146.                         // No, just use all text as value link.
  147.                         tp.data = link;
  148.                         tp.defaultdata = "%{"+tp.data+"=null}";
  149.                     }
  150.                    
  151.                     // skip forward
  152.                     CHARINDEX = end;
  153.                 } else {
  154.                     // Just text!
  155.                     buffer.append(CHAR);
  156.                 }
  157.             }
  158.            
  159.             // If there is something left in the buffer, finish it.
  160.             if(buffer.length() > 0) {
  161.                 String str = buffer.toString();
  162.                 TextPiece tp = new TextPiece();
  163.                 tp.data = str;
  164.                 pieces.add(tp);
  165.             }
  166.         }
  167.        
  168.         // Finds the next index of 'searched', then returns it. -1 if it cant be found.
  169.         private final int findNext(String string, int start, char searched) {
  170.             for(int i = start; i <= string.length(); i++) {
  171.                 if(string.charAt(i) == searched)
  172.                     return i;
  173.             }
  174.             return -1;
  175.         }
  176.        
  177.         // Safely peeking around in a string without getting IndexOutOfBoundsException's.
  178.         private final char peek(String string, int index, char def) {
  179.             if(index < 0)
  180.                 return def;
  181.             if(index >= string.length())
  182.                 return def;
  183.             return string.charAt(index);
  184.         }
  185.     }
  186.    
  187.     /** A piece of the template. **/
  188.     public static abstract class Piece {
  189.         // empty class
  190.     }
  191.    
  192.     /** A piece representing simple text. **/
  193.     public static class TextPiece extends Piece {
  194.         String data;
  195.        
  196.         @Override
  197.         public String toString() {
  198.             return "TextPiece:\""+data+"\"";
  199.         }
  200.     }
  201.    
  202.     /** A piece that will be replaced by some value when the template is rendered. **/
  203.     public static class LinkPiece extends Piece {
  204.         String data;
  205.         String defaultdata;
  206.        
  207.         @Override
  208.         public String toString() {
  209.             return "LinkPiece:\""+data+"\"|\""+defaultdata+"\"";
  210.         }
  211.     }
  212.    
  213.     /**
  214.      * "renders" a template using the given data-map.
  215.      * @param template The template to render.
  216.      * @param data The data to insert into the template.
  217.      * @param writer The writer to output the template to.
  218.      * @throws IOException If something goes wrong.
  219.      **/
  220.     public static final void render(Template template, Map<String, String> data, Writer writer) throws IOException {
  221.         // Go trough all pieces...
  222.         for(Piece piece : template.pieces) {
  223.             // If it is a text-piece...
  224.             if(piece instanceof TextPiece) {
  225.                 // Write it out!
  226.                 writer.append(((TextPiece) piece).data);
  227.             }
  228.            
  229.             // If it is a link-piece...
  230.             if(piece instanceof LinkPiece) {
  231.                 // Get the name of the 'link'...
  232.                 String link = ((LinkPiece) piece).data;
  233.                
  234.                 // Get the value from the data-map...
  235.                 String replace = data.get(link);
  236.                
  237.                 // Is the value NULL?
  238.                 if(replace == null) {
  239.                     // Yes, write the default value stored inside the LinkPiece.
  240.                     writer.append(((LinkPiece) piece).defaultdata);
  241.                 } else {
  242.                     // No, write the actual data!
  243.                     writer.append(replace);
  244.                 }
  245.             }
  246.         }
  247.        
  248.         // Flush! Note that we do NOT close the writer,
  249.         // as one may want to append multiple templates.
  250.         writer.flush();
  251.     }
  252.    
  253. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement