領先一步
VMware 提供培訓和認證,以加速您的進展。
了解更多Groovy 語言是建立領域特定語言 (DSL) 的絕佳平台。一個好的 DSL 可以使程式更簡潔、更具表達力,並提高程式設計師的生產力。然而,直到現在,這些 DSL 並未在 Groovy-Eclipse 編輯器中獲得直接支援。當大量使用 DSL 時,標準 IDE 功能(如內容輔助、搜尋、浮動提示和導航)就會失去價值。長期以來,可以編寫 Eclipse 外掛程式來擴展 Groovy-Eclipse,但這是一種繁重的方法,需要 Eclipse API 的特定知識。現在 Groovy-Eclipse 支援DSL 描述器 (DSLDs),在 Groovy-Eclipse 中支援自訂 DSL 將變得更加容易。
3.m + 2.yd + 2.mi - 1.km
這是一個簡單且具表達力的 DSL,但是當您在 Groovy-Eclipse 的 Groovy 編輯器中輸入此程式碼時(為了簡潔起見,假設 $url
已在其他地方定義)
[caption id="attachment_8774" align="aligncenter" width="179"][/caption]
您會看到底線且沒有浮動提示,這表示編輯器無法靜態解析 DSL 的表達式。使用 DSLD,可以教導編輯器一些這些自訂 DSL 背後的語義,並為浮動提示提供文件
[caption id="attachment_8775" align="aligncenter" width="683"][/caption]
若要為距離 DSL 建立 DSL 描述器,您只需在 Groovy 專案中新增一個檔案,其檔案副檔名為 .dsld,且內容如下
currentType( subType( Number ) ).accept {
property name:"m", type:"Distance",
doc: """A <code>meter</code> from <a href="$url">$url</a>"""
}
這個腳本表示每當編輯器中目前正在評估的類型是 java.lang.Number
的子類型時,將 'm
' 屬性新增至該類型,其類型為 Distance
。currentType(subType(Number))
部分稱為切入點,而包含對 property
呼叫的程式碼區塊稱為貢獻區塊。稍後會詳細介紹這些概念。
上面的腳本片段不是完整的 DSLD。它只新增了 'm
' 屬性。若要完成實作,您可以利用 Groovy 語法的完整功能
currentType( subType( Number ) ).accept {
[ m: "meter", yd: "yard", cm: "centimerter", mi: "mile", km: "kilometer"].each {
property name:it.key, type:"Distance",
doc: """A <code>${it.value}</code> from <a href="$url">$url</a>"""
}
}
這個簡單的範例表明,相對較小的腳本可以建立一些強大的 DSL 支援。
DSLD 增強了 Groovy-Eclipse 的 類型推斷引擎,該引擎在編輯時在背景執行。DSLD 由 IDE 評估,並在必要時由推斷引擎查詢。
DSLD 腳本包含一組切入點,每個切入點都與一個或多個貢獻區塊相關聯。切入點大致描述了在哪裡需要增強類型推斷(即,哪些類型在哪些上下文中),而貢獻區塊描述了如何增強它(即,應新增哪些屬性和方法)。
許多切入點可用,並且在 DSLD 文件中詳細描述了它們以及範例。隨著我們開始了解人們將如何建立腳本以及他們需要哪種操作,可用切入點的集合可能會在未來版本的 DSLD 中擴展。
貢獻區塊是 Groovy 程式碼區塊,透過 accept
方法與切入點相關聯。您可以在貢獻區塊內執行的兩個主要操作是 property
(我們之前已介紹過)和 method
,它會將方法新增至貢獻區塊中正在分析的類型。
術語切入點借鑑自 面向切面程式設計 (AOP)。實際上,DSLD 可以被認為是一種 AOP 語言。DSLD 與典型的 AOP 語言(如 AspectJ)之間的主要區別在於,DSLD 在正在編輯的程式的抽象語法樹上運作,而像 AspectJ 這樣的語言則在已編譯程式的 Java 位元組碼上運作。
Codehaus 的 wiki 上有完整的 DSLD 文件。在這裡,我將簡要描述如何開始使用 DSLD。入門步驟如下:
http://dist.codehaus.org/groovy/distributions/greclipse/snapshot/e3.6/
currentType(subType('groovy.lang.GroovyObject')).accept {
property name : 'newProp', type : String,
provider : 'Sample DSL',
doc : 'This is a sample. You should see this in content assist for all GroovyObjects:<pre>newProp</pre>'
}
在 DSLD 內部,您應該會看到特定於 DSLD 的內容輔助和浮動提示(這來自步驟 2 中新增的 meta-DSLD 腳本)。它看起來會像這樣:
this.newProp
您應該看到 newProp
已正確突出顯示,並且浮動提示將顯示 DSLD 中的文件,它看起來應該像這樣:您可以從 Groovy -> DSLD 偏好設定頁面檢視和管理工作區中的所有 DSLD:
從這裡,您可以啟用/停用個別腳本,以及選擇要編輯的腳本。
重要提示:由於實作 DSLD 時尋找和修正錯誤可能有點隱晦,因此強烈建議您執行以下操作
腳本的編譯和執行階段問題將顯示在這兩個位置之一。
對於更大的範例,讓我們看看 Grails 框架。Grails 限制 DSL 提供了一種宣告式方式來驗證 Grails 網域類別。它清晰簡潔,但如果沒有對此 DSL 的直接編輯支援,Grails 程式設計師將依賴外部文件,並且可能直到執行階段才會意識到語法錯誤。我們可以建立 DSLD 來解決這個問題
// only available in STS 2.7.0 and above
supportsVersion(grailsTooling:"2.7.0")
// a generic grails artifact is a class that is in a grails project, is not a script and is in one of the 'grails-app' folders
def grailsArtifact = { String folder ->
sourceFolderOfCurrentType("grails-app/" + folder) &
nature("com.springsource.sts.grails.core.nature") & (~isScript())
}
// define the various kinds of grails artifacts
def domainClass = grailsArtifact("domain")
// we only require domainClass, but we can also reference other kinds of artifacts here
def controllerClass = grailsArtifact("controllers")
def serviceClass = grailsArtifact("services")
def taglibClass = grailsArtifact("taglib")
// constraints
// The constraints DSL is only applicable inside of the static "constraints" field declaration
inClosure() & (domainClass & enclosingField(name("constraints") & isStatic()) &
(bind(props : properties()) & // 'bind' props to the collection of properties in the domain class
currentTypeIsEnclosingType())).accept {
provider = "Grails Constraints DSL" // this value will appear in content assist
// for each non-static property, there are numerous constraints "methods" that are available
// define them all here
for (prop in props) {
if (prop.isStatic()) {
continue
}
if (prop.type == ClassHelper.STRING_TYPE) {
method isStatic: true, name: prop.name, params: [blank:Boolean], useNamedArgs:true
method isStatic: true, name: prop.name, params: [creditCard:Boolean], useNamedArgs:true
method isStatic: true, name: prop.name, params: [email:Boolean], useNamedArgs:true
method isStatic: true, name: prop.name, params: [url:Boolean], useNamedArgs:true
method isStatic: true, name: prop.name, params: [matches:String], useNamedArgs:true
} else if (prop.type.name == Date.name) {
method isStatic: true, name: prop.name, params: [max:Date], useNamedArgs:true
method isStatic: true, name: prop.name, params: [min:Date], useNamedArgs:true
} else if (ClassHelper.isNumberType(prop.type)) {
method isStatic: true, name: prop.name, params: [max:Number], useNamedArgs:true
method isStatic: true, name: prop.name, params: [min:Number], useNamedArgs:true
method isStatic: true, name: prop.name, params: [scale:Number], useNamedArgs:true
} else if (prop.type.implementsInterface(ClassHelper.LIST_TYPE)) {
method isStatic: true, name: prop.name, params: [maxSize:Number], useNamedArgs:true
method isStatic: true, name: prop.name, params: [minSize:Number], useNamedArgs:true
}
method isStatic: true, name: prop.name, params: [unique:Boolean], useNamedArgs:true
method isStatic: true, name: prop.name, params: [size:Integer], useNamedArgs:true
method isStatic: true, name: prop.name, params: [notEqual:Object], useNamedArgs:true
method isStatic: true, name: prop.name, params: [nullable:Boolean], useNamedArgs:true
method isStatic: true, name: prop.name, params: [range:Range], useNamedArgs:true
method isStatic: true, name: prop.name, params: [inList:List], useNamedArgs:true
}
}
如果您複製上面的 DSLD 腳本並將其新增到 Grails 專案中的 DSLD 檔案中,STS 將會學習限制語言。例如,在以下簡單的網域類別中,您可以在限制區塊內獲得以下內容輔助:
可以調整上面的腳本以新增自訂文件。
即使大多數 Groovy 和 Grails 使用者不實作自己的 DSL,他們也會使用 DSL(在 Grails、Gaelyk 中,透過 建構器 等)。因此,即使大多數 STS 使用者不會建立自己的 DSLD,他們也將受益於其他人建立的 DSLD。我們將與程式庫和 DSL 開發人員密切合作,以便為 Groovy 生態系統的不同部分建立常見的 DSLD。
您可以期望在即將推出的 Groovy-Eclipse 版本中看到對流行的基於 Groovy 的框架的支援大幅增加。
DSLD 語言的核心實作現在已可供使用,但隨著我們更多地了解使用者的需求以及他們想要支援的 DSL 類型,我們將對其進行調整。我們將實作更多切入點,擴展文件,並努力在 Groovy-Eclipse 本身中發佈一些標準 DSLD。
請試用此處或 wiki 上介紹的一些 DSLD,並在此部落格文章、我們的 問題追蹤器 或 Groovy-Eclipse 郵件列表 中向我們提供意見回饋。