一:DSL 概念html
指的是用於一個特定領域的語言(功能領域、業務領域)。在這個給出的概念中有 3個重點:數據庫
只用於一個特定領域,而非全部通用領域,好比 Java / C++就是用於通用領域,而不可被稱爲 DSL,一樣也不可把 Groovy稱爲 DSL。編程
語言,必須通過編寫後纔可發揮它的功能。好比:五線譜編寫後成曲譜; ANT編寫用於編譯; SVN命令編寫後可對資源庫進行操做; Shell編程; SQL編程; PL-SQL編程等等。閉包
忽略具體的運行環境(媒介),能夠是紙、 XML文件、命令行、 Shell、數據庫等。編程語言
二:Groovy對 DSL的支持gradle
Groovy不是 DSL,而是通用的編程語言。但 Groovy卻對編寫出一個全新的 DSL提供了良好的支持,這些支持都來自於 Groovy自身語法的特性,好比:ui
不須要 class定義,直接執行腳本this
Groovy語法的簡潔spa
Groovy提供了更多通俗易懂的方法命令行
省略()和;等
等等
Groovy自身不是 DSL。 Groovy官方已經發布了較多基於 Groovy書寫的 DSL,好比 GANT, GORM, XMLBuilder, HtmlBuilder等等。
三:咱們的目標
實現一種使用 Groovy語法書寫、用於構建 HTML的(其實就是 HtmlBuilder)的簡單 DSL,以下:
html {
head {
meta {
}
}
body {
table (style:'margin:5px;') {
tr ('class':'trClass', style:'padding:5px;') { td {'Cell1'} td {'Cell2'} td {'Cell3'} } } } }
這段代碼比較容易讓人懂,很容易讓人將 HTML與之對應起來。具體怎麼實現可以經過這一段 DSL代碼輸出原始的 HTML呢?主要基於 Groovy的如下幾個特性:
Groovy腳本,不用定義 class
Groovy的 invokeMethod方法
方法可不書寫()
語句末尾省略;分號
不書寫 return
四:代碼分析
meta {
}
//這段代碼的含義爲:調用 meta方法,參數爲一個閉包,閉包不執行任何代碼。
table (style:'margin:5px;') { } //這段代碼的含義爲:調用 table方法,第一個參數爲 Map,第二個參數爲閉包。 tr ('class':'trClass', style:'padding:5px;') { td {'Cell1'} td {'Cell2'} td {'Cell3'} } //這段代碼的含義爲: //調用 tr方法,第一個參數爲 Map,第二個參數爲閉包。 //閉包中,調用了 3 個 td方法,參數都爲一個閉包;閉包中直接返回了一個字符串。
五:代碼實現
將代碼解讀了之後,再結合 invokeMethod就很容易實現了,具體代碼以下:
def invokeMethod(String name, args) {
print "<${name}" args.each { arg -> if (arg instanceof Map) { arg.each { print " ${it.key} ='${it.value}' " } } else if (arg instanceof Closure) { print '>' arg.delegate = this def value = arg.call() if (value) { print "${value}" } } } println "</${name}>" } html { head { meta { } } body { table (style:'margin:5px;') { tr ('class':'trClass', style:'padding:5px;') { td {'Cell1'} td {'Cell2'} td {'Cell3'} } } } }
六:運行結果
<html><head><meta></meta> </head> <body><table style ='margin:5px;' > <tr class ='trClass' style ='padding:5px;' > <td>Cell1</td> <td>Cell2</td> <td>Cell3</td> </tr> </table> </body> </html>
七:結論基於Groovy自身的語法簡潔和衆多特性,實現一個專屬的DSL仍是蠻簡單的。