added a little experimental spike of a text and markup based template library for internal DSLs for templating (which external DSLs like Jade / Razor / Velocity / Erb / JSP style) could layer on top of. Mails to follow shortly :)
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
namespace std.template
|
||||
|
||||
import std.io.*
|
||||
|
||||
/**
|
||||
* Represents a generic API to templates which should be usable
|
||||
* in JavaScript in a browser or on the server side stand alone or in a web app etc.
|
||||
*
|
||||
* To make things easier to implement in JS this namespace won't refer to any java.io or servlet
|
||||
* stuff
|
||||
*/
|
||||
trait Template {
|
||||
var printer: Printer
|
||||
|
||||
/** Renders the template to the output printer */
|
||||
fun render(): Unit
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the output of a template which is a stream of objects
|
||||
* usually strings which then write to some underlying output stream
|
||||
* such as a java.io.Writer on the server side.
|
||||
*
|
||||
* We abstract away java.io.* APIs here to make the JS implementation simpler
|
||||
*/
|
||||
trait Printer {
|
||||
fun print(value: Any): Unit
|
||||
//fun print(text: String): Unit
|
||||
}
|
||||
|
||||
class NullPrinter() : Printer {
|
||||
//override fun print(text: String) = none()
|
||||
override fun print(value: Any) {
|
||||
throw UnsupportedOperationException("No Printer defined on the Template")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for template implementations to hold any helpful behaviour
|
||||
*/
|
||||
abstract class TemplateSupport : Template {
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for templates generating text output
|
||||
* by printing values to some underlying Printer which
|
||||
* will typically output to a String, File, stream etc.
|
||||
*/
|
||||
abstract class TextTemplate() : TemplateSupport, Printer {
|
||||
override var printer: Printer = NullPrinter()
|
||||
|
||||
fun String.plus(): Unit {
|
||||
printer.print(this)
|
||||
}
|
||||
|
||||
//override fun print(value: String) = printer.print(value)
|
||||
|
||||
override fun print(value: Any) = printer.print(value)
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
namespace std.template.html
|
||||
|
||||
import std.*
|
||||
import std.template.*
|
||||
import std.io.*
|
||||
import std.util.*
|
||||
import java.io.*
|
||||
import java.util.*
|
||||
|
||||
|
||||
trait Factory<T> {
|
||||
fun create() : T
|
||||
}
|
||||
|
||||
abstract class Element
|
||||
|
||||
class TextElement(val text : String) : Element
|
||||
|
||||
abstract class Tag(val name : String) : Element {
|
||||
val children = ArrayList<Element>()
|
||||
val attributes = HashMap<String, String>()
|
||||
|
||||
protected fun initTag<T : Element>(init : T.()-> Unit) : T
|
||||
where class object T : Factory<T> {
|
||||
val tag = T.create()
|
||||
tag.init()
|
||||
children.add(tag)
|
||||
return tag
|
||||
}
|
||||
}
|
||||
|
||||
abstract class TagWithText(name : String) : Tag(name) {
|
||||
fun String.plus() {
|
||||
children.add(TextElement(this))
|
||||
}
|
||||
}
|
||||
|
||||
class HTML() : TagWithText("html") {
|
||||
class object : Factory<HTML> {
|
||||
override fun create() = HTML()
|
||||
}
|
||||
|
||||
fun head(init : Head.()-> Unit) = initTag(init)
|
||||
|
||||
fun body(init : Body.()-> Unit) = initTag(init)
|
||||
}
|
||||
|
||||
class Head() : TagWithText("head") {
|
||||
class object : Factory<Head> {
|
||||
override fun create() = Head()
|
||||
}
|
||||
|
||||
fun title(init : Title.()-> Unit) = initTag(init)
|
||||
}
|
||||
|
||||
class Title() : TagWithText("title")
|
||||
|
||||
abstract class BodyTag(name : String) : TagWithText(name) {
|
||||
}
|
||||
|
||||
class Body() : BodyTag("body") {
|
||||
class object : Factory<Body> {
|
||||
override fun create() = Body()
|
||||
}
|
||||
|
||||
fun b(init : B.()-> Unit) = initTag(init)
|
||||
fun p(init : P.()-> Unit) = initTag(init)
|
||||
fun h1(init : H1.()-> Unit) = initTag(init)
|
||||
|
||||
fun a(href : String) {
|
||||
a(href) {}
|
||||
}
|
||||
|
||||
fun a(href : String, init : A.()-> Unit) {
|
||||
val a = initTag(init)
|
||||
a.href = href
|
||||
}
|
||||
}
|
||||
|
||||
class B() : BodyTag("b")
|
||||
class P() : BodyTag("p")
|
||||
class H1() : BodyTag("h1")
|
||||
|
||||
class A() : BodyTag("a") {
|
||||
var href: String? = null
|
||||
/*
|
||||
var href : String
|
||||
get() = attributes["href"]
|
||||
set(value) { attributes["href"] = value }
|
||||
*/
|
||||
}
|
||||
|
||||
fun body(init: Body.()-> Unit): Body {
|
||||
val elem = Body()
|
||||
elem.init()
|
||||
return elem
|
||||
}
|
||||
|
||||
fun html(init : HTML.()-> Unit) : HTML {
|
||||
val html = HTML()
|
||||
html.init()
|
||||
return html
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for templates which generate markup (XML or HTML for example)
|
||||
* which have additional helper methods for escaping markup etc
|
||||
*/
|
||||
abstract class MarkupTemplate() : TemplateSupport {
|
||||
|
||||
override fun render() {
|
||||
val markup = markup()
|
||||
print(markup)
|
||||
}
|
||||
|
||||
/** Returns the markup to be rendered */
|
||||
abstract fun markup(): Iterable<Element>
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
// Server side Java IO code to avoid coupling
|
||||
// the core template code to java.* for easier JS porting
|
||||
namespace std.template.io
|
||||
|
||||
import std.template.*
|
||||
import java.io.Writer
|
||||
import java.io.OutputStream
|
||||
import java.io.OutputStreamWriter
|
||||
import java.io.PrintStream
|
||||
import java.io.StringWriter
|
||||
|
||||
/**
|
||||
* A Printer implementation which uses a Writer
|
||||
*/
|
||||
class WriterPrinter(val writer: Writer) : Printer {
|
||||
|
||||
override fun print(value: Any) {
|
||||
// TODO should be using a formatter to do the conversion
|
||||
writer.write(value.toString())
|
||||
}
|
||||
}
|
||||
|
||||
fun Template.renderToText(): String {
|
||||
val buffer = StringWriter()
|
||||
renderTo(buffer)
|
||||
return buffer.toString().sure()
|
||||
}
|
||||
|
||||
fun Template.renderTo(writer: Writer): Unit {
|
||||
this.printer = WriterPrinter(writer)
|
||||
this.render()
|
||||
}
|
||||
|
||||
fun Template.renderTo(os: OutputStream): Unit = renderTo(OutputStreamWriter(os))
|
||||
Reference in New Issue
Block a user