Kotlin Academy · Lektion

Bygg en typsäker HTML-/Config-DSL

Implementera en enkel konfigurations-DSL med builder-mönster och extension-lambdor.

Lektion 3 av 414 steg

Bygg en typsäker HTML-/Config-DSL är en gratis lektion i Kotlin Academy på CoddyKit. Detta är lektion 3 av 4. Du kan läsa vilka 3 lektioner som helst i den här lärvägen kostnadsfritt i sin helhet – därefter låser CoddyKit PRO upp alla lektioner, plus praktisk övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Den ingår i lärvägen för Kotlin Academy, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i Kotlin Academy innehåller totalt 4 lektioner.

Mål: en praktisk DSL

Vi ska bygga en minimal men realistisk HTML-builder-DSL i Kotlin. Samma mönster kan användas för konfigurationer, testfixturer och rapportbyggare. Resultatet är ett typsäkert, IDE-vänligt API som ersätter strängkonkatenering.

Definiera basklassen för taggar

Alla HTML-element har samma grundstruktur: ett namn, attribut och underordnade element. Börja med en basklass:

open class Tag(val name: String) {
    val attrs = mutableMapOf<String, String>()
    val children = mutableListOf<Tag>()
    fun render(indent: Int = 0): String {
        val pad = " ".repeat(indent)
        val attrStr = if (attrs.isEmpty()) "" else " " + attrs.entries.joinToString(" ") { "${it.key}=\"${it.value}\"" }
        val body = children.joinToString("\n") { it.render(indent + 2) }
        return "$pad<$name$attrStr>\n$body\n$pad</$name>"
    }
}

Tillämpa @DslMarker

Markera alla builder-klasser så att inre omfång inte av misstag kan anropa metoder i yttre omfång:

@DslMarker
annotation class HtmlDsl

@HtmlDsl class Html : Tag("html")
@HtmlDsl class Head : Tag("head")
@HtmlDsl class Body : Tag("body")
@HtmlDsl class Div  : Tag("div")
@HtmlDsl class P   : Tag("p")

Lägg till builder-funktioner

Varje taggklass får en extension-funktion som skapar en underordnad tagg, tillämpar blocket och lägger till den bland de underordnade elementen:

fun Html.head(block: Head.() -> Unit) = Head().also { it.block(); children += it }
fun Html.body(block: Body.() -> Unit) = Body().also { it.block(); children += it }
fun Body.div(block: Div.() -> Unit) = Div().also { it.block(); children += it }
fun Div.p(text: String) = P().also { it.attrs["text"] = text; children += it }

html-builder på toppnivå

Ge en startpunkt på toppnivå som skapar rotelementet och tillämpar användarens block:

fun html(block: Html.() -> Unit): Html {
    val root = Html()
    root.block()
    return root
}

Använda DSL:en

Resultatet är en ren och lättläst DSL:

val page = html {
    head { }
    body {
        div {
            p("Hello, DSL!")
        }
    }
}
println(page.render())

Lägga till attribut

Lägg till en attr-hjälpfunktion för att ange godtyckliga attribut på ett smidigt sätt:

fun Tag.attr(key: String, value: String) { attrs[key] = value }

// Usage
div {
    attr("class", "container")
    p("Content")
}

Konfigurations-DSL-mönstret

Samma mönster fungerar för konfigurationsobjekt. Använd domänklasser i stället för HTML-taggar:

class ServerConfig {
    var host = "localhost"
    var port = 8080
    var db: DbConfig? = null
    fun database(block: DbConfig.() -> Unit) { db = DbConfig().apply(block) }
}
fun server(block: ServerConfig.() -> Unit) = ServerConfig().apply(block)

Kapsla in och sätt samman

Eftersom varje builder-funktion returnerar det skapade objektet kan du fritt sätta samman builders. DSL:ens kapslingsdjup motsvarar djupet i datahierarkin.

Felprevention med hjälp av typer

Typsystemet tvingar fram strukturen: du kan inte anropa body { } inuti en Head eftersom Head inte har någon body-extension-funktion. Ogiltiga strukturer blir kompileringsfel.

Rendera och testa

Eftersom DSL:en producerar ett vanligt Kotlin-objektträd är rendering och testning enkelt: anropa render() och kontrollera resultatsträngen, eller traversera objektträdet i tester.

Utöka DSL:en senare

Att lägga till nya taggar eller konfigurationsalternativ kräver endast nya extension-funktioner på den lämpliga mottagarklassen. Befintliga anropsställen påverkas inte – öppet/slutet i praktiken.

Snabbkontroll

Vad gör en Kotlin-HTML-/konfigurations-DSL ”typsäker”?

Sammanfattning: Bygga en typsäker DSL

Viktiga steg:

  • Definiera builder-klasser för varje nivå i hierarkin
  • Använd @DslMarker för att förhindra läckage mellan mottagare
  • Skriv extension-funktioner som skapar, konfigurerar och lägger till underordnade objekt
  • Exponera en funktion på toppnivå som startpunkt
  • Rendering och testning fungerar med vanliga Kotlin-objekt
Gratis att börja

Lär dig Kotlin med en AI-lärare – gratis

Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.

Kurser
51
Lektioner
203

Vanliga frågor

Är lektionen ”Bygg en typsäker HTML-/Config-DSL” gratis?

Ja – du kan läsa vilka 3 lektioner som helst i lärvägen Kotlin Academy, inklusive ”Bygg en typsäker HTML-/Config-DSL”, kostnadsfritt i sin helhet här på webben. Därefter låser CoddyKit PRO upp alla lektioner, plus interaktiv övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Kursen i Kotlin Academy innehåller totalt 4 lektioner.

Vad lär jag mig i ”Bygg en typsäker HTML-/Config-DSL”?

Implementera en enkel konfigurations-DSL med builder-mönster och extension-lambdor. Ni övar på Kotlin Academy med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.

Behöver jag någon erfarenhet för att börja lära mig Kotlin Academy?

Du behöver inga förkunskaper. Utbildningen i Kotlin Academy på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 3 av 4.

Hur lång tid tar lektionen ”Bygg en typsäker HTML-/Config-DSL”?

De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.

Kan jag skriva och köra kod i den här Kotlin Academy-lektionen?

Ja. Varje Kotlin Academy-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.

Alla lektioner i den här kursen

  1. Lambda med receiver: grunden för DSL:er
  2. @DslMarker: förhindra läckage mellan receivers
  3. Bygg en typsäker HTML-/Config-DSL
  4. Testa och utveckla DSL:er utan att bryta användare
← Tillbaka till Kotlin Academy