Kotlin Academy · leksjon

Bygge en typesikker HTML-/Config-DSL

Implementer en enkel konfigurasjons-DSL med builder-mønstre og utvidelseslambdaer.

Leksjon 3 av 414 trinn

Bygge en typesikker HTML-/Config-DSL er en gratis leksjon i Kotlin Academy på CoddyKit. Dette er leksjon 3 av 4. Du kan lese valgfritt 3 leksjoner fra denne læringsstien gratis i sin helhet – deretter låser CoddyKit PRO opp alle leksjoner, samt praktisk øving med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i Kotlin Academy, og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i Kotlin Academy inneholder totalt 4 leksjoner.

Mål: en praktisk DSL

Vi skal bygge en minimal, men realistisk HTML-builder-DSL i Kotlin. De samme mønstrene gjelder for alle konfigurasjons-, testdata- eller rapportbuildere. Resultatet er et typesikkert og IDE-vennlig API som erstatter strengsammenføyning.

Definere basisklassen for tagger

Alle HTML-elementer har samme grunnstruktur: et navn, attributter og barn. Start med en basisklasse:

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>"
    }
}

Bruke @DslMarker

Merk alle builder-klasser, slik at indre områder ikke utilsiktet kan kalle metoder fra ytre områder:

@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")

Legge til builder-funksjoner

Hver taggklasse får en utvidelsesfunksjon som oppretter en underordnet tagg, bruker blokken og legger den til blant barna:

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å

Tilby et inngangspunkt på toppnivå som oppretter rotelementet og bruker brukerblokken:

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

Bruke DSL-en

Resultatet er en ren og lettlest DSL:

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

Legge til attributter

Legg til en attr-hjelpefunksjon for å angi vilkårlige attributter på en flytende måte:

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

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

Mønster for konfigurasjons-DSL

Det samme mønsteret fungerer for konfigurasjonsobjekter. I stedet for HTML-tagger bruker du domeneklasser:

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)

Nøsting og sammensetning

Fordi hver builder-funksjon returnerer objektet som ble opprettet, kan du fritt sette sammen buildere. Nøstingsdybden i DSL-en samsvarer med dybden i datahierarkiet.

Feilforebygging med typer

Typesystemet håndhever strukturen: Du kan ikke kalle body { } inne i en Head fordi Head ikke har noen body-utvidelsesfunksjon. Ugyldige strukturer gir kompileringstidsfeil.

Rendring og testing

Fordi DSL-en produserer et vanlig Kotlin-objekttre, er rendring og testing enkelt: Kall render() og kontroller resultatstrengen, eller gå gjennom objekttreet i tester.

Utvidelse av DSL-en senere

Det kreves bare nye utvidelsesfunksjoner på den aktuelle receiver-klassen for å legge til nye tagger eller konfigurasjonsalternativer. Eksisterende kallesteder påvirkes ikke – åpen/lukket i praksis.

Rask kontroll

Hva gjør en Kotlin HTML/config-DSL «typesikker»?

Oppsummering: Bygging av en typesikker DSL

Viktige trinn:

  • Definer builder-klasser for hvert nivå i hierarkiet
  • Annoter med @DslMarker for å forhindre lekkasje mellom receivere
  • Skriv utvidelsesfunksjoner som oppretter, konfigurerer og legger til underordnede objekter
  • Eksponer en funksjon på toppnivå som inngangspunkt
  • Gjengivelse og testing fungerer på vanlige Kotlin-objekter
Gratis å komme i gang

Lær deg Kotlin med en AI-veileder – gratis

Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.

Kurs
51
Leksjoner
203

Ofte stilte spørsmål

Er leksjonen «Bygge en typesikker HTML-/Config-DSL» gratis?

Ja – du kan lese valgfritt 3 av leksjonene i læringsstien Kotlin Academy, inkludert «Bygge en typesikker HTML-/Config-DSL», gratis i sin helhet her på nettet. Deretter låser CoddyKit PRO opp alle leksjoner, samt interaktiv øving med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Kurset i Kotlin Academy inneholder totalt 4 leksjoner.

Hva lærer jeg i «Bygge en typesikker HTML-/Config-DSL»?

Implementer en enkel konfigurasjons-DSL med builder-mønstre og utvidelseslambdaer. Du øver på Kotlin Academy med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.

Trenger jeg erfaring for å begynne med Kotlin Academy?

Ingen tidligere erfaring er nødvendig. Kotlin Academy på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 3 av 4.

Hvor lang tid tar leksjonen «Bygge en typesikker HTML-/Config-DSL»?

De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.

Kan jeg skrive og kjøre kode i denne Kotlin Academy-leksjonen?

Ja. Alle Kotlin Academy-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.

Alle leksjonene i dette kurset

  1. Lambda med mottaker: Grunnlaget for DSL-er
  2. @DslMarker: Hindre lekkasje av mottakere
  3. Bygge en typesikker HTML-/Config-DSL
  4. Teste og videreutvikle DSL-er uten å bryte brukere
← Tilbake til Kotlin Academy