Skip to content

Instantly share code, notes, and snippets.

@hexx
Created March 3, 2013 08:07
Show Gist options
  • Save hexx/5075273 to your computer and use it in GitHub Desktop.
Save hexx/5075273 to your computer and use it in GitHub Desktop.
import scala.language.dynamics
import scala.util.DynamicVariable
sealed trait Node {
def render: String
}
case class ElementNode(name: String, attributes: Map[String, String], children: List[Node]) extends Node {
def render = {
val as = attributes.mapValues("\"" + _ + "\"")
s"""<$name${as.map { case (l, r) => s" $l=$r" }.mkString}>${children.map(_.render).mkString}</$name>"""
}
}
case class TextNode(text: String) extends Node {
def render = text
}
trait HtmlDSL {
val nodes = new DynamicVariable[List[Node]](null)
val attributes = new DynamicVariable[List[(String, String)]](null)
object % extends Dynamic {
def selectDynamic(name: String) = applyDynamic(name)()
def applyDynamic(name: String)(body: => Unit) = {
val (as, ns) =
nodes.withValue(List()) {
attributes.withValue(List()) {
body
(attributes.value.toMap, nodes.value.reverse)
}
}
nodes.value = ElementNode(name, as, ns) :: nodes.value
}
}
def $(as: (String, String)*) = attributes.value = attributes.value ++ as
def t(text: String) = nodes.value = TextNode(text) :: nodes.value
def dsl(body: => Unit) = nodes.withValue(List()) {
body
nodes.value.head
}
}
object Sample extends HtmlDSL {
val html = dsl {
%html {
%head {
%link $("rel" -> "stylesheet", "href" -> "style.css")
%title t("タイトルだよ")
}
%body {
for (i <- 1 to 3) {
%p t(s"${i}だよ")
}
%p {
%a ($("href" -> "http://ubiregi.com"), t("ユビレジ"))
}
}
}
}
def print = println(html.render)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment