2010-02-23 101 views
2

我正在尋找創建一個新的DSL使用groovy,但我很難找出最佳的方式來閱讀dsl的groovy。我希望用戶能夠創建一個dsl並實際運行dsl,而無需與應用程序代碼進行交談。Groovy閱讀/運行DSL

game.groovy(如DSL):

import com.foo.groovygame.Game 

go north 10 
search 
find ana 
turn right 

我希望用戶能夠說:

groovy game.groovy 

,它會運行遊戲。我知道我可以這樣做:

groovy Game game.groovy 

但我寧願能夠直接運行dsl。

我注意到this blog筆者使用

Ronald.init(this) 

我可以做這樣的事情,並有init方法處理來自DSL的比賽,但我想知道,這是最好的方法?它似乎有點馬虎。我真的很喜歡處理這個的紅寶石方式。您可以簡單地創建一個dsl並在dsl中指定require'foo'。

回答

1

我今天花了一些時間試驗完成你所描述的不同方式,並且我決定在你所鏈接的「完美風暴」博客上提出的建議可能是最直接,最不復雜的。我的第一個想法是在Game類中創建一個靜態初始化器,它將自動處理初始化遊戲,但不幸的是,儘管Game類只是從'import'語句加載的(如通過運行-verbose:在JAVA_OPTS中設置的類),靜態初始化程序不會執行,直到以某種方式引用Game類爲止。這需要您的game.groovyDSL中的new Game()行。

即使假設你沒有問題,處理遊戲DSL中函數和屬性的唯一方法是以某種方式爲遊戲類添加支持。在靜態初始化器中,您將無法直接訪問遊戲類,但可以訪問其超類:groovy.lang.Script。您可以將方法go()search()添加到Script.metaClass,但是您將其添加到Script的所有實例中,這幾乎肯定不是您想要的。

這導致需要用遊戲DSL作爲參數調用一些方法Game,la Game.init (this)。有一兩件事可以做,使之一點視覺上清潔劑是靜態地導入遊戲的init方法:

import static com.foo.groovygame.Game.init 

init (this); 
go north, 10 
... 

最後一點:你仍然需要在你的DSL,這意味着法之間的逗號使用Groovy語法參數,要求法無括號參數等:

go north, 10 
search() 
find ana 
turn right 

我很感興趣,如果其他人能夠拿出解決方案,清潔劑,甚至只是一些方法來使靜態初始化,而不必被執行請參閱封閉類。

1

我真的不用瘋狂使用編譯器語法來實現DSL--對不起,我知道一些人喜歡它,我很樂意承認這是一個可愛的技巧,但是編寫自己的解析器非常容易,爲什麼不呢做它?然後,您的文本中不會有隨機逗號和下劃線。

下面是一個簡單的竅門,我用來實現一個簡單的語法像你描述的一個:

首先,看你的命令 - 注意,大部分是在「動詞名詞PARAMS」格式

此映射真的很好地方法名,對象名,則params

所以一個很好的程序是:

split sentence into string array s 

for a line with a single word (if s.length == 1): 
    instantiate an object with that name 
    call a default method on that object 
    done 
for a line with more than one word 
    instantiate the object s[1] 
    call method s[0] with s[2...] as parameters 
    done 

這種簡單的5-10左右線解析r將解決您的許多DSL類型問題。除此之外,您可以輕鬆添加功能:

如果參數(2 ...)採用「name = value」形式,則掃描名爲「name」的參數並傳遞該參數的「value」。這可能不適用於這種特定情況,但可以適用於其他用途。

如果您的單詞命令需要參數,則嘗試將s [0]實例化爲一個類,即使有多個單詞。如果失敗,請回到上面的多字算法。

我有一種情況,在實例化後需要保持物體。我使用的語法:

find person:ana 

,並從那時起(語法可以通過保持一個表映射全日空的人,一起試圖實例化對象檢查該表可以固定回原來的語法) ,ana是person類的一個實例(換句話說,在實例化「person」並調用方法「find」之後,我將該person對象存儲在名爲「ana」的散列中,下次他們使用命令如:

talk ana 

它會搜索散列f首先,抓住存儲在那裏的對象,並在該現有對象上調用「talk」(在這一點上,它可以檢查ana是否設置了「發現」標誌,否則它可能會返回不同的消息)。通過這種方式,您可以擁有多個朋友,每個朋友都擁有自己的所有狀態信息。

這個系統有一些限制,但仍比Ruby風格的DSL靈活得多,實際上並不難實現。

0

RTBarnard的答案似乎是最好的。腳本執行後進行一些處理的最佳方式是什麼?

Ronald.init this 

go right 
back ten 
...etc... 

所有的DSL已經被處理後,再羅納德應該做一些額外的工作,但不必說一些諸如Ronald.run()用戶。