Earnest beginnings.
This commit is contained in:
@@ -0,0 +1,136 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>com.samskivert</groupId>
|
||||||
|
<artifactId>jmustache</artifactId>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
<version>1.1-SNAPSHOT</version>
|
||||||
|
<name>jmustache</name>
|
||||||
|
<description>A Java implementation of the Mustache templating language.</description>
|
||||||
|
<url>http://code.google.com/p/jmustache/</url>
|
||||||
|
<issueManagement>
|
||||||
|
<url>http://code.google.com/p/jmustache/issues/list</url>
|
||||||
|
</issueManagement>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>org.sonatype.oss</groupId>
|
||||||
|
<artifactId>oss-parent</artifactId>
|
||||||
|
<version>5</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<licenses>
|
||||||
|
<license>
|
||||||
|
<name>GNU Lesser General Public License (LGPL), Version 2.1</name>
|
||||||
|
<url>http://www.fsf.org/licensing/licenses/lgpl.txt</url>
|
||||||
|
<distribution>repo</distribution>
|
||||||
|
</license>
|
||||||
|
</licenses>
|
||||||
|
|
||||||
|
<developers>
|
||||||
|
<developer>
|
||||||
|
<id>samskivert</id>
|
||||||
|
<name>Michael Bayne</name>
|
||||||
|
<email>mdb@samskivert.com</email>
|
||||||
|
</developer>
|
||||||
|
</developers>
|
||||||
|
|
||||||
|
<scm>
|
||||||
|
<connection>scm:svn:http://jmustache.googlecode.com/svn/trunk/</connection>
|
||||||
|
<developerConnection>scm:svn:https://jmustache.googlecode.com/svn/trunk/</developerConnection>
|
||||||
|
<url>http://jmustache.googlecode.com/svn/trunk/</url>
|
||||||
|
</scm>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<version>4.8.1</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>2.3.2</version>
|
||||||
|
<configuration>
|
||||||
|
<source>1.5</source>
|
||||||
|
<target>1.5</target>
|
||||||
|
<fork>true</fork>
|
||||||
|
<showDeprecation>true</showDeprecation>
|
||||||
|
<showWarnings>true</showWarnings>
|
||||||
|
<!-- yes, those quoted spaces are a workaround sanctioned by the Maven idiocracy -->
|
||||||
|
<compilerArgument>-Xlint" "-Xlint:-serial" "-Xlint:-path</compilerArgument>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-resources-plugin</artifactId>
|
||||||
|
<version>2.4.3</version>
|
||||||
|
<configuration>
|
||||||
|
<encoding>UTF-8</encoding>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<version>2.6</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
|
<version>2.7</version>
|
||||||
|
<configuration>
|
||||||
|
<quiet>true</quiet>
|
||||||
|
<show>public</show>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
|
<version>2.3.1</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-install-plugin</artifactId>
|
||||||
|
<version>2.3.1</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-deploy-plugin</artifactId>
|
||||||
|
<version>2.5</version>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<profiles>
|
||||||
|
<profile>
|
||||||
|
<id>release-sign-artifacts</id>
|
||||||
|
<activation>
|
||||||
|
<property><name>performRelease</name><value>true</value></property>
|
||||||
|
</activation>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-gpg-plugin</artifactId>
|
||||||
|
<version>1.1</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>sign-artifacts</id>
|
||||||
|
<phase>verify</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>sign</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
<configuration>
|
||||||
|
<keyname>mdb@samskivert.com</keyname>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</profile>
|
||||||
|
</profiles>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
package com.samskivert.mustache;
|
||||||
|
|
||||||
|
import java.io.Reader;
|
||||||
|
import java.io.StringReader;
|
||||||
|
import java.io.Writer;
|
||||||
|
import java.lang.reflect.Array;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides <a href="http://mustache.github.com/">Mustache</a> templating services.
|
||||||
|
*/
|
||||||
|
public class Mustache
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Compiles the supplied template into a repeatedly executable intermediate form.
|
||||||
|
*/
|
||||||
|
public static Template compile (String template)
|
||||||
|
{
|
||||||
|
return compile(new StringReader(template));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compiles the supplied template into a repeatedly executable intermediate form.
|
||||||
|
*/
|
||||||
|
public static Template compile (Reader template)
|
||||||
|
{
|
||||||
|
return null; // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
private Mustache () {} // no instantiateski
|
||||||
|
|
||||||
|
/** A simple segment that reproduces a string. */
|
||||||
|
protected static class StringSegment extends Template.Segment {
|
||||||
|
public StringSegment (String text) {
|
||||||
|
_text = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void execute (Object ctx, Writer out) {
|
||||||
|
write(out, _text);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final String _text;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A segment that substitutes the contents of a variable. */
|
||||||
|
protected static class VariableSegment extends Template.Segment {
|
||||||
|
public VariableSegment (String name) {
|
||||||
|
_name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void execute (Object ctx, Writer out) {
|
||||||
|
Object value = getValue(ctx, _name);
|
||||||
|
// TODO: configurable behavior on missing values
|
||||||
|
if (value != null) {
|
||||||
|
write(out, String.valueOf(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final String _name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A segment that represents a section. */
|
||||||
|
protected static class SectionSegment extends Template.Segment {
|
||||||
|
public SectionSegment (String name, Template.Segment[] segs) {
|
||||||
|
_name = name;
|
||||||
|
_segs = segs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void execute (Object ctx, Writer out) {
|
||||||
|
Object value = getValue(ctx, _name);
|
||||||
|
if (value == null) {
|
||||||
|
return; // TODO: configurable behavior on missing values
|
||||||
|
}
|
||||||
|
if (value instanceof Iterable<?>) {
|
||||||
|
Iterable<?> iable = (Iterable<?>)value;
|
||||||
|
for (Object elem : iable) {
|
||||||
|
executeSegs(elem, out);
|
||||||
|
}
|
||||||
|
} else if (value instanceof Boolean) {
|
||||||
|
if ((Boolean)value) {
|
||||||
|
executeSegs(ctx, out);
|
||||||
|
}
|
||||||
|
} else if (value.getClass().isArray()) {
|
||||||
|
for (int ii = 0, ll = Array.getLength(value); ii < ll; ii++) {
|
||||||
|
executeSegs(Array.get(value, ii), out);
|
||||||
|
}
|
||||||
|
} else if (value instanceof Iterator<?>) {
|
||||||
|
Iterator<?> iter = (Iterator<?>)value;
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
executeSegs(iter.next(), out);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
executeSegs(value, out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void executeSegs (Object ctx, Writer out) {
|
||||||
|
for (Template.Segment seg : _segs) {
|
||||||
|
seg.execute(ctx, out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String _name;
|
||||||
|
protected Template.Segment[] _segs;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
package com.samskivert.mustache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An exception thrown when an error occurs parsing or executing a Mustache template.
|
||||||
|
*/
|
||||||
|
public class MustacheException extends RuntimeException
|
||||||
|
{
|
||||||
|
public MustacheException (String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MustacheException (Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MustacheException (String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
package com.samskivert.mustache;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.io.Writer;
|
||||||
|
import java.util.Deque;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a compiled template.
|
||||||
|
*/
|
||||||
|
public class Template
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Executes this template with the supplied data, writing the results to the supplied writer.
|
||||||
|
*
|
||||||
|
* <p>The data can be any tree of objects. Given a name <code>foo</code>, the following
|
||||||
|
* mechanisms are supported for resolving its value (and are sought in this order):
|
||||||
|
* <ul>
|
||||||
|
* <li>If the object is a {@link Map}, {@link Map#get} will be called with the string
|
||||||
|
* <code>foo</code> as the key.
|
||||||
|
* <li>A method named <code>foo</code> in the supplied object (with non-void return value).
|
||||||
|
* <li>A method named <code>getFoo</code> in the supplied object (with non-void return value).
|
||||||
|
* <li>A field named <code>foo</code> in the supplied object.
|
||||||
|
* </ul>
|
||||||
|
* </p><p> The field type, method return type, or map value type should correspond to the
|
||||||
|
* desired behavior if the resolved name corresponds to a section. {@link Boolean} is used for
|
||||||
|
* showing or hiding sections without binding a sub-context. Arrays, {@link Iterator} and
|
||||||
|
* {@link Iterable} implementations are used for sections that repeat, with the context bound
|
||||||
|
* to the elements of the array, iterator or iterable. Lambdas are current unsupported, though
|
||||||
|
* they would be easy enough to add if desire exists. See the <a
|
||||||
|
* href="http://mustache.github.com/mustache.5.html">Mustache documentation</a> for more
|
||||||
|
* details on section behavior. </p>
|
||||||
|
*
|
||||||
|
* @throws MustacheException if an error occurs while writing the template.
|
||||||
|
*/
|
||||||
|
public void execute (Object data, Writer out) throws MustacheException
|
||||||
|
{
|
||||||
|
for (Segment seg : _segs) {
|
||||||
|
seg.execute(data, out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes this template with the supplied data, returning the results as a string. See {@link
|
||||||
|
* #execute(Object, Writer).
|
||||||
|
*
|
||||||
|
* @throws MustacheException if an error occurs while writing the template.
|
||||||
|
*/
|
||||||
|
public String execute (Object data) throws MustacheException
|
||||||
|
{
|
||||||
|
StringWriter out = new StringWriter();
|
||||||
|
execute(data, out);
|
||||||
|
return out.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Template (Segment[] segs)
|
||||||
|
{
|
||||||
|
_segs = segs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A template is broken into segments. */
|
||||||
|
protected static abstract class Segment
|
||||||
|
{
|
||||||
|
abstract void execute (Object ctx, Writer out);
|
||||||
|
|
||||||
|
protected Object getValue (Object ctx, String name) {
|
||||||
|
// TODO: support things other than values
|
||||||
|
return ((Map<?,?>)ctx).get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static void write (Writer out, String data) {
|
||||||
|
try {
|
||||||
|
out.write(data);
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
throw new MustacheException(ioe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final Segment[] _segs;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user