moved old experimental code into the sandbox

This commit is contained in:
James Strachan
2012-03-21 08:56:43 +00:00
parent 669c7ec326
commit 81294d43ae
6 changed files with 0 additions and 0 deletions
@@ -0,0 +1,59 @@
package kotlin.template
import kotlin.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,181 @@
package kotlin.template.html
import kotlin.*
import kotlin.template.*
import kotlin.io.*
import kotlin.util.*
import java.io.*
import java.util.*
trait Factory<T> {
fun create() : T
}
abstract class Element {
abstract fun appendTo(builder: StringBuilder): Unit
}
class TextElement(val text : String) : Element() {
override fun appendTo(builder: StringBuilder) {
builder.append(text)
}
}
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 = try {
T.create()
} catch (e: NullPointerException) {
val typeName = javaClass.getName()
throw UnsupportedOperationException("No class object create() method for $typeName")
}
tag.init()
children.add(tag)
return tag
}
override fun appendTo(builder: StringBuilder): Unit {
builder.append("<")
builder.append(name)
if (!attributes.isEmpty()) {
for (e in attributes.entrySet()) {
if (e != null) {
builder.append(" ${e.getKey()}=\"${e.getValue()}\"")
}
}
}
if (children.isEmpty()) {
builder.append("/>")
} else {
builder.append(">")
for (c in children) {
c.appendTo(builder)
}
builder.append("<")
builder.append(name)
builder.append(">")
}
}
fun toString(): String {
val builder = StringBuilder()
appendTo(builder)
return builder.toString().sure()
}
}
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") {
class object : Factory<Title> {
override fun create() = 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 object : Factory<B> {
override fun create() = B()
}
}
class P() : BodyTag("p") {
class object : Factory<P> {
override fun create() = P()
}
}
class H1() : BodyTag("h1") {
class object : Factory<H1> {
override fun create() = H1()
}
}
class A() : BodyTag("a") {
class object : Factory<A> {
override fun create() = A()
}
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
package kotlin.template.io
import kotlin.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))
@@ -0,0 +1,46 @@
package kotlin.template
import kotlin.*
import kotlin.template.io.*
import kotlin.io.*
import kotlin.util.*
import kotlin.test.*
import java.util.*
class EmailTemplate(var name: String = "James", var time: Date = Date()) : TextTemplate() {
override fun render() {
print("Hello there $name and how are you? Today is $time. Kotlin rocks")
}
}
class MoreDryTemplate(var name: String = "James", var time: Date = Date()) : TextTemplate() {
override fun render() {
+"Hey there $name and how are you? Today is $time. Kotlin rocks"
}
}
class TemplateCoreTest() : TestSupport() {
fun testDefaultValues() {
val text = EmailTemplate().renderToText()
assert {
println(text)
text.startsWith("Hello there James")
}
}
fun testDifferentValues() {
val text = EmailTemplate("Andrey").renderToText()
assert {
println(text)
text.startsWith("Hello there Andrey")
}
}
fun testMoreDryTemplate() {
val text = MoreDryTemplate("Alex").renderToText()
assert {
println(text)
text.startsWith("Hey there Alex")
}
}
}
@@ -0,0 +1,118 @@
package kotlin.template.html
import kotlin.*
import kotlin.template.*
import kotlin.template.io.*
import kotlin.io.*
import kotlin.util.*
import kotlin.test.*
import java.util.*
val justBody = body {
+"Hello world"
}
fun result(args : List<String>) =
html {
head {
title {+"XML encoding with Kotlin"}
}
body {
h1 {+"XML encoding with Kotlin"}
p {+"this format can be used as an alternative markup to XML"}
// an element with attributes and text content
a(href = "http://jetbrains.com/kotlin") {+"Kotlin"}
// mixed content
p {
+"This is some"
b {+"mixed"}
+"text. For more see the"
a(href = "http://jetbrains.com/kotlin") {+"Kotlin"}
+"project"
}
p {+"some text"}
// content generated by
p {
for (arg in args)
+arg
}
}
}
/** Create a bad element which doesn't have a class object create() method */
class BadElem() : BodyTag("bad") {
}
/** Creates a bad body to test out badly defined elements */
class BadBody() : BodyTag("badBody") {
fun bad(init : BadElem.()-> Unit) = initTag(init)
}
fun badBody(init: BadBody.()-> Unit): BadBody {
val elem = BadBody()
elem.init()
return elem
}
class TemplateHtmlTest() : TestSupport() {
fun testJustBody() {
assertEquals("<body>Hello world<body>", justBody.toString())
}
fun testEmbeddedSimpleBody() {
val e = body {
+"body with text"
}
assertEquals("<body>body with text<body>", e.toString())
}
fun testEmbeddedBodyWithNestedBold() {
val e = body {
b{
+"this is bold"
}
}
assertEquals("<body><b>this is bold<b><body>", e.toString())
}
fun testEmbeddedBodyWithNestedLinks() {
val e = body {
a("http://jetbrains.com/kotlin") {
+"link text"
}
}
assertEquals("<body><a href=\"http://jetbrains.com/kotlin\">link text<a><body>", e.toString())
}
fun testHtmlFunction() {
val e = result(arrayList("a", "b", "c"))
assertEquals("""<html><head><title>XML encoding with Kotlin<title><head><body><h1>XML encoding with Kotlin<h1><p>this format can be used as an alternative markup to XML<p><a href="http://jetbrains.com/kotlin">Kotlin<a><b>mixed<b><a href="http://jetbrains.com/kotlin">Kotlin<a><p>This is sometext. For more see theproject<p><p>some text<p><p>abc<p><body><html>""", e.toString())
}
fun testEmbeddedFunction() {
val e = html {
head {
title {+"XML encoding with Kotlin"}
}
body {
a("http://jetbrains.com/kotlin")
}
}
assertEquals("<html><head><title>XML encoding with Kotlin<title><head><body><a href=\"http://jetbrains.com/kotlin\"/><body><html>", e.toString())
}
fun testBadlyDefinedElement() {
failsWith<UnsupportedOperationException>{
val e = badBody {
bad{
+"Bad Element Text"
}
}
println("bad body: $e")
}
}
}
@@ -0,0 +1,29 @@
/*
* Copyright 2010-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package kotlin.template;
import kotlin.template.html.*;
import junit.framework.TestSuite;
/**
*/
public class TemplateTestAll {
public static TestSuite suite() {
return new TestSuite(TemplateCoreTest.class, TemplateHtmlTest.class);
}
}