我爱编程

Kotlin 进阶之路10 领域特定语言 DSL

2018-06-04  本文已影响144人  香沙小熊

Kotlin 进阶之路 目录

DSL 的概念

- HTML、Gradle、SQL等等

DSL的特点

HTML Kotlin

import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty

class MapDelegate(val map: MutableMap<String, String>) : ReadWriteProperty<Any, String> {
    override fun getValue(thisRef: Any, property: KProperty<*>): String {
        return map[property.name] ?: ""
    }

    override fun setValue(thisRef: Any, property: KProperty<*>, value: String) {
        map[property.name] = value
    }
}
 interface Node {
    fun render(): String
}
fun html(block: Tag.() -> Unit): Tag {
    return Tag("html").apply(block)
}

fun Tag.head(block: Head.() -> Unit) {
    this + Head().apply(block)
}

fun Tag.body(block: Body.() -> Unit) {
    this + Body().apply(block)
}

class StringNode(val content: String) : Node {
    override fun render() = content
}

class Head : Tag("head")

class Body : Tag("body") {
    var id by MapDelegate(proerties)

    var `class` by MapDelegate(proerties)
}
open class Tag(val name: String) : Node {

    val children = ArrayList<Node>()

    val proerties = HashMap<String, String>()

    operator fun String.invoke(value: String) {
        proerties[this] =value
    }

    operator fun String.invoke(block:Tag.()->Unit){
        children.add(Tag(this).apply(block))
    }

    operator fun String.unaryPlus(){
        children.add(StringNode(this))
    }

    operator fun plus(node: Node){
        children.add(node)
    }



    // <html id ="htmlId' style=''><head></head><body></body></html>
    override fun render(): String {
        return StringBuffer()
                .append("<")
                .append(name)
                .let { stringBuffer ->
                    if (!this.proerties.isEmpty()) {
                        stringBuffer.append(" ")
                        this.proerties.forEach {
                            stringBuffer.append(it.key)
                                    .append("=\"")
                                    .append(it.value)
                                    .append("\" ")
                        }
                    }
                    stringBuffer
                }
                .append(">")
                .let { stringBuffer ->
                    children.map(Node::render).map(stringBuffer::append)
                    stringBuffer
                }
                .append("</$name>")
                .toString()
    }
}

fun main(args: Array<String>) {
//    Tag("html").apply {
//    proerties["id"] = "HtmlId"
//    children.add(Tag("head"))
//}.render().let ( ::println )

//    html {
//        proerties["id"] = "HtmlId"
//        children.add(Tag("head"))
//
//    }.render().let(::println)

    html {
        "id"("HtmlId") //执行 Tag中的invoke方法
        "head"{
            "id"("headId")
        }
        body {
            id = "bodyId"
            `class` = "bodyClass"
            "a"{
                "href"("https://www.kotliner.cn")
                +"Kotlin 中文博客"
            }
        }
        "div"{
        }
    }.render().let(::println)
}

运行结果

<html id="HtmlId" ><head id="headId" ></head><body id="bodyId" class="bodyClass" ><a href="https://www.kotliner.cn" >Kotlin 中文博客</a></body><div></div></html>

Gradle Kotlin 脚本

group = "cn.kotliner.kotlin"
version = "1.0-SNAPSHOT"

buildscript {
    extra["kotlin_version"] = "1.1.2"

    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${extra["kotlin_version"]}")
    }
}

apply {
    plugin("java")
    plugin("kotlin")
}

configure<JavaPluginConvention>{
    setSourceCompatibility(1.5)
}

repositories {
    mavenCentral()
}

dependencies {
    compile("org.jetbrains.kotlin:kotlin-stdlib-jre8:${extra["kotlin_version"]}")
    testCompile("junit", "junit", "4.12")
}
上一篇下一篇

猜你喜欢

热点阅读