美文网首页我爱编程
Kotlin 进阶之路10 领域特定语言 DSL

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

作者: 香沙小熊 | 来源:发表于2018-06-04 17:45 被阅读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")
    }
    

    相关文章

      网友评论

        本文标题:Kotlin 进阶之路10 领域特定语言 DSL

        本文链接:https://www.haomeiwen.com/subject/hplesftx.html