Kotlin
Beginner
1 min read
Building DSLs with Extension Lambdas
Example
@DslMarker
annotation class HtmlDsl
@HtmlDsl
class Tag(val name: String) {
private val children = mutableListOf<String>()
private val attrs = mutableMapOf<String, String>()
fun attr(key: String, value: String) { attrs[key] = value }
fun text(content: String) { children += content }
fun child(tag: Tag) { children += tag.render() }
fun render(): String {
val attrStr = attrs.entries.joinToString(" ") { (k, v) -> "$k=\"$v\"" }
val open = if (attrStr.isEmpty()) "<$name>" else "<$name $attrStr>"
return "$open${children.joinToString("")}</$name>"
}
}
fun tag(name: String, block: Tag.() -> Unit): Tag {
val t = Tag(name)
t.block()
return t
}
// buildString DSL from stdlib
fun buildReport(items: List<Pair<String, Int>>): String = buildString {
appendLine("=== Report ===")
items.forEach { (label, value) ->
append(" ").append(label).append(": ").appendLine(value)
}
append("Total: ").append(items.sumOf { it.second })
}
fun main() {
val div = tag("div") {
attr("class", "container")
child(tag("h1") { text("Hello, DSL!") })
child(tag("p") { text("Kotlin makes this clean.") })
}
println(div.render())
println()
val report = buildReport(listOf("Sales" to 500, "Refunds" to 30, "Net" to 470))
println(report)
}