0Pricing
Kotlin Academy · Lekcja

Budowanie bezpiecznego typowo DSL HTML/Config

Zaimplementuj prosty DSL konfiguracji, korzystając ze wzorców buildera i lambd rozszerzających.

Budowanie bezpiecznego typowo DSL HTML/Config to bezpłatna lekcja Kotlin Academy na CoddyKit. To lekcja 3 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Kotlin Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Kotlin Academy zawiera 4 lekcji w sumie.

Cel: praktyczny język DSL

Zbudujemy minimalny, ale realistyczny język DSL do tworzenia kodu HTML w Kotlinie. Te same wzorce mają zastosowanie do dowolnej konfiguracji, struktury danych testowych lub buildera raportów. Rezultatem będzie bezpieczny typowo interfejs API przyjazny dla IDE, który zastąpi konkatenację ciągów znaków.

Definiowanie bazowej klasy Tag

Wszystkie elementy HTML mają wspólną strukturę: nazwę, atrybuty i elementy podrzędne. Należy rozpocząć od klasy bazowej:

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

Zastosowanie @DslMarker

Należy oznaczyć wszystkie klasy builderów, aby zakresy wewnętrzne nie mogły przypadkowo wywoływać metod z zewnętrznego zakresu:

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

Dodawanie funkcji buildera

Każda klasa tagu otrzymuje funkcję rozszerzającą, która tworzy podrzędny tag, stosuje blok i dodaje go do elementów podrzędnych:

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 }

Builder html najwyższego poziomu

Należy udostępnić punkt wejścia najwyższego poziomu, który tworzy element główny i stosuje blok użytkownika:

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

Używanie języka DSL

Rezultatem jest przejrzysty i czytelny język DSL:

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

Dodawanie atrybutów

Należy dodać pomocnik attr do płynnego ustawiania dowolnych atrybutów:

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

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

Wzorzec DSL konfiguracji

Ten sam wzorzec działa w przypadku obiektów konfiguracji. Zamiast tagów HTML należy użyć klas domenowych:

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)

Zagnieżdżanie i komponowanie

Ponieważ każda funkcja buildera zwraca utworzony obiekt, można swobodnie komponować buildery. Głębokość zagnieżdżenia DSL odpowiada głębokości hierarchii danych.

Zapobieganie błędom za pomocą typów

System typów wymusza strukturę: nie można wywołać body { } wewnątrz Head, ponieważ Head nie ma funkcji rozszerzającej body. Nieprawidłowe struktury powodują błędy w czasie kompilacji.

Renderowanie i testowanie

Ponieważ język DSL tworzy zwykłe drzewo obiektów Kotlina, renderowanie i testowanie są proste: należy wywołać render() i sprawdzić wynikowy ciąg znaków albo przejść po drzewie obiektów w testach.

Późniejsze rozszerzanie DSL

Dodanie nowych tagów lub opcji konfiguracji wymaga jedynie nowych funkcji rozszerzających dla odpowiedniej klasy odbiornika. Istniejące miejsca wywołań pozostają bez zmian — zasada otwarte-zamknięte w praktyce.

Szybkie sprawdzenie

Co sprawia, że DSL HTML/konfiguracji w Kotlinie jest „bezpieczny typowo”?

Podsumowanie: budowanie DSL bezpiecznego typowo

Najważniejsze kroki:

  • Zdefiniowanie klas builderów dla każdego poziomu hierarchii
  • Dodanie adnotacji @DslMarker, aby zapobiec wyciekowi odbiornika
  • Napisanie funkcji rozszerzających, które tworzą, konfigurują i dodają obiekty podrzędne
  • Udostępnienie funkcji wejściowej na najwyższym poziomie
  • Renderowanie i testowanie działają na zwykłych obiektach Kotlina

Często zadawane pytania

Czy lekcja „Budowanie bezpiecznego typowo DSL HTML/Config” jest bezpłatna?

Tak — pełny tekst „Budowanie bezpiecznego typowo DSL HTML/Config” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Kotlin Academy, przejdź na CoddyKit PRO. Kurs Kotlin Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Budowanie bezpiecznego typowo DSL HTML/Config”?

Zaimplementuj prosty DSL konfiguracji, korzystając ze wzorców buildera i lambd rozszerzających. Ćwiczysz Kotlin Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Kotlin Academy?

Nie wymagamy żadnego doświadczenia. Kotlin Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 4.

Ile czasu zajmuje lekcja „Budowanie bezpiecznego typowo DSL HTML/Config”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Kotlin Academy?

Tak. Każda lekcja Kotlin Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Lambda z odbiorcą: podstawa DSL
  2. @DslMarker: zapobieganie wyciekaniu odbiorcy
  3. Budowanie bezpiecznego typowo DSL HTML/Config
  4. Testowanie i rozwijanie DSL bez łamania zgodności użytkowników
← Powrót do Kotlin Academy