0Pricing
Kotlin Academy · Lezione

Costruire una DSL HTML/Config type-safe

Implementi una semplice DSL di configurazione usando pattern builder e lambda di estensione.

Costruire una DSL HTML/Config type-safe è una lezione Kotlin Academy gratuita su CoddyKit. Questa è la lezione 3 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Kotlin Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Kotlin Academy include 4 lezioni in totale.

Obiettivo: una DSL pratica

Creeremo una DSL builder HTML minimale ma realistica in Kotlin. Gli stessi pattern si applicano a qualsiasi builder per configurazioni, fixture di test o report. Il risultato è un'API type-safe e compatibile con l'IDE, che sostituisce la concatenazione di stringhe.

Definire la classe base Tag

Tutti gli elementi HTML condividono la stessa struttura: un nome, attributi e figli. Iniziamo con una classe base:

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

Applicare @DslMarker

Contrassegni tutte le classi builder, in modo che gli scope interni non possano chiamare accidentalmente i metodi dello scope esterno:

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

Aggiungere le funzioni builder

Ogni classe dei tag riceve una funzione di estensione che crea un tag figlio, applica il blocco e lo aggiunge ai figli:

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 di primo livello

Fornisca un punto di ingresso di primo livello che crei l'elemento radice e applichi il blocco dell'utente:

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

Usare la DSL

Il risultato è una DSL pulita e leggibile:

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

Aggiungere gli attributi

Aggiunga un helper attr per impostare gli attributi arbitrari in modo fluido:

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

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

Pattern DSL per la configurazione

Lo stesso pattern funziona per gli oggetti di configurazione. Al posto dei tag HTML, si usano classi del dominio:

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)

Annidare e comporre

Poiché ogni funzione builder restituisce l'oggetto creato, è possibile comporre liberamente i builder. La profondità dell'annidamento della DSL corrisponde alla profondità della gerarchia dei dati.

Prevenire gli errori con i tipi

Il sistema dei tipi impone la struttura: non è possibile chiamare body { } all'interno di un Head, perché Head non dispone di una funzione di estensione body. Le strutture non valide provocano errori in fase di compilazione.

Rendering e test

Poiché la DSL produce un semplice albero di oggetti Kotlin, il rendering e i test sono immediati: chiami render() e verifichi la stringa risultante, oppure attraversi l'albero di oggetti nei test.

Estendere la DSL in un secondo momento

Per aggiungere nuovi tag o opzioni di configurazione sono sufficienti nuove funzioni di estensione sulla classe receiver appropriata. I punti di utilizzo esistenti non vengono modificati: il principio aperto/chiuso nella pratica.

Verifica rapida

Che cosa rende una DSL HTML/config di Kotlin «type-safe»?

Riepilogo: costruire una DSL type-safe

Passaggi principali:

  • Definire classi builder per ogni livello della gerarchia
  • Annotarle con @DslMarker per impedire la fuoriuscita del receiver
  • Scrivere funzioni di estensione che creano, configurano e aggiungono oggetti figli
  • Esporre una funzione di ingresso di livello superiore
  • Il rendering e i test operano su semplici oggetti Kotlin

Domande Frequenti

La lezione «Costruire una DSL HTML/Config type-safe» è gratuita?

Sì — il testo completo di «Costruire una DSL HTML/Config type-safe» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Kotlin Academy, passa a CoddyKit PRO. Il corso Kotlin Academy include 4 lezioni in totale.

Cosa imparerò in «Costruire una DSL HTML/Config type-safe»?

Implementi una semplice DSL di configurazione usando pattern builder e lambda di estensione. Eserciti Kotlin Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Kotlin Academy?

Non è richiesta alcuna esperienza precedente. Kotlin Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 3 di 4.

Quanto tempo richiede la lezione «Costruire una DSL HTML/Config type-safe»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Kotlin Academy?

Sì. Ogni lezione Kotlin Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Lambda con receiver: la base delle DSL
  2. @DslMarker: impedire la fuoriuscita del receiver
  3. Costruire una DSL HTML/Config type-safe
  4. Testare ed evolvere le DSL senza interrompere gli utenti
← Torna a Kotlin Academy