2016-08-04 37 views
2

我目前正在構建一個小的DSL,它需要指定key = value對中的一組屬性,但是這些密鑰可能包含破折號' - '或句點''。我似乎無法讓它工作。對帶有無效密鑰的DSL使用groovy映射

煮沸我本質上嘗試傳遞一個Map作爲委託給一個閉包,但是這個語法一直讓我着迷。

作爲一個例子,考慮這樣的:

def map = [:] 

map.with { 
    example1 = 123 
    //exam-ple2 = 123 
    //'exam-ple3' = 123 
    //(exam-ple4) = 123 
    exam.ple5 = 123 
    //'exam.ple6' = 123 
} 

實施例1是精細,關鍵字等於值和容易讀取。例2和例4是編譯器根據二進制表達式編譯的。例3和例6是常量表達式,不會被編譯。例5將編譯,但在運行時生成一個NPE。

我可以使用變通方法,例如將Map作爲參數傳遞給閉包,這給了我例3和例6,但是它的冗長讓我很煩惱。

有沒有人有任何想法如何整齊地DSL屬性映射?

BTW:我從Java調用不是常規的DSL,所以在分析方面的技巧必須是java :)

更新1:在inital意見和答案後..

所以腳本由GroovyShell評估爲DelegatingScript,其中代表是Java對象。封閉包含來自.properties文件的屬性,需要在不同的上下文中進行定義,例如,

env { 
    server-name=someHost1 
    database.name=someHost2 
    clientName=someHost3 
} 

委派(Java)的對象將讀取該塊,作爲

public void env(Closure closure) { 
    Map map = new HashMap(); 
    closure.setDelegate(map); 
    closure.setResolveStrategy(Closure.DELEGATE_ONLY); 
    closure.call(); 
    ... do something with map... 

}

現在的用戶(即不是我)可能會從原來的屬性文件複製到腳本更改名稱,因此我寧願他們可以做到這一點,而不必編輯太多,因爲它肯定會導致錯別字。

正如我所說我也有例3和6海灣紅色爲好,但肯定的,蒂姆,我忘了隱含的吧:)

現在我已經改變了格式的字符串,因此DSL使用多寫像

env ''' 
    server-name=someHost1 
    database.name=someHost2 
    clientName=someHost3 
''' 

也就是說,直插式字符串而不是關閉,然後讀取字符串,並使用標準的java.util.Properties:

public void env(String envString) { 
    Properties properties = new Properties; 
    properties.load(new StringReader(envString)) 
    ....etc 

}

雖然這個工程,具有封閉和M的組合最後一行字符串是目前唯一的缺點。

+0

你可以這樣解釋:「解析方必須是java'? 由於內部groovy DSL依賴groovy語法分析器 像地圖元素分配這裏,你將如何解析它與Java? 如果你打電話groovy,無論如何不會在groovy方面做到這一點? – ARA

+0

'it.'exam-ple2'= 123' –

回答

0

在地圖聲明,Groovy中解析標識符,比如example1example2字符串鍵到地圖:

[ example1: 1, example2: 2 ] 

.with{}情況下,它可能使用setProperty(property, value)機制。


但你的案件的特點表現exam.pleexam-ple。這些表達式有優先權,因此,Groovy會嘗試先解決它們(可能分別類似於exam.getProperty('ple')exam.minus(ple))。

你有一些語法的替代品,但你必須要清楚,以常規什麼都應該是字符串鍵,什麼是其他表達式:

def map = [ 
    'exam.ple4' : 4, // direct map declaration 
    example5 : 5 // unambiguous key declaration: no quotes needed 
] 

map.with { 
    example1 = 1 
    put 'exam.ple2', 2 // ambiguous, needs quotes 
    it.'exam-ple3' = 3 // as per @TimYates suggestion 
} 

assert map['exam-ple3'] == 3 
assert map.'exam.ple2' == 2 
assert map['exam.ple4'] == 4 
assert map.example5 == 5 // again, no quotes needed for key