私もgroovyのDSLの専門家ではありませんが、少し遊んでいるので、あなたのケースは実行可能だと思います。しかし、それは大きいです。
書き込み
verify generalTab { ... }
Groovyは次のように解決するようです
verify( generalTab({ ... }) )
したがって、必要な方法に近い方法は、メソッドが欠落している呼び出しをインターセプトすることです('generalTab'は私にはhtmlコンポーネントIDのようです。間違っている場合は、修正してください)。
必要なもの:verify()
メソッドとmethodMissing()
メソッド。
あなたif
とelse
s...ええと、私たちはそれをwhen
とに交換できotherwise
ますか?groovy自身の予約語を避けるためだけに;-)
後のこれらの二重の言葉はif
、全体をかなり醜くします。ドットまたは1つの単語だけを使用できるとよいでしょう。
when dataValidFor clientName then addInfoToReport otherwise addErrorToReport
に解決します
when(dataValidFor).clientName(then).addInfoToReport(otherwise).addErrorToReport
これは解析するのがおかしいでしょう。あなたが次のようなことをすることができればそれはより良いです:
when dataValidFor('clientName') then addInfoToReport otherwise addErrorToReport
私は次のことをしました:
report = [:]
// the closure passed as a parameter to the html component
Closure runningVerification
// the closure that handles adding info to report
Closure addInfoToReport = { Data data ->
report[data] = "[INFO] Field '$data.field' from component '$data.component' valid: $data.valid"
}
// the closure that handles adding errors to report
Closure addErrorToReport = { Data data ->
report[data] = "[ERROR] Field '$data.field' from component '$data.component' valid: $data.valid"
}
/*
* The when() method will receive a data object and returns
* a map to be handled by the 'then' and the 'otherwise' cases
*
* The 'then' and 'otherwise' must passes closures to this method
*/
def when(Data data) {
data.component = runningVerification.binding.htmlComponent
[ then:
{ Closure thenAction ->
if (data.valid) thenAction(data)
[ otherwise:
{ Closure otherwiseAction ->
if (!data.valid) otherwiseAction(data)
}
]
}
]
}
/*
* Handles missing method calls. We need this to keep track of the
* 'generalTab', the HTML component whose tests are being ran against
*/
def methodMissing(String method, args)
{
runningVerification = args[0]
runningVerification.delegate = this
runningVerification.binding.htmlComponent = method // awful
runningVerification()
}
/*
* Verify the status of the validation for html component. The
* argument is useless, it needs to access the report variable in
* the binding
*/
def verify(dataValidation) {
def errors = report.findAll { !it.key.valid }.size()
report.each { println it.value }
print "Result: "
if (errors == report.size()) {
println "Every test failed"
} else if (errors == 0) {
println "Success"
} else {
println "At least one test failed"
}
}
class Data { String component; String field; Boolean valid }
Data dataValidFor(String property) {
new Data(valid: new Random().nextInt() % 2, field: property)
}
Data confidentialData(String property) {
new Data(valid: new Random().nextInt() % 2, field: property)
}
verify generalTab {
when dataValidFor('clientName') then addInfoToReport otherwise addErrorToReport
when dataValidFor('clientCountry') then addInfoToReport otherwise addErrorToReport
when confidentialData('clientId') then addInfoToReport otherwise addErrorToReport
}
そしてそれは動作します。それは(ランダムに)印刷します:
[INFO] Field 'clientName' from component 'generalTab' valid: true
[ERROR] Field 'clientCountry' from component 'generalTab' valid: false
[INFO] Field 'clientId' from component 'generalTab' valid: true
Result: At least one test failed
かなり醜くなりました。これは、概念実証のようなものです。BaseScripts、GroovyShellを使用してクラスを分離し、他のクラスなどに委任する必要があります。また、レポートなどのクラスを考慮して、きちんとモデル化する必要があります。しかし、これまでのところ、それは実行可能だと思います。しかし、かなり大きいです。
私の読書の提案:
Guillaume Laforgeは、火星のロボットのスクリプトDSLを示しています:http:
//www.slideshare.net/glaforge/going-to-mars-with-groovy-domainspecific-languages
Groovyのコマンド表現の芸術:http:
//www.canoo.com/blog/2011/12/08/the-art-of-groovy-command-expressions-in-dsls/
これは、私が個人的に使用するためにJFugueを介してDSLを終了することができた後、今日groovyリストに送信した電子メールです:http:
//groovy.329449.n5.nabble.com/Method-chaining-in-DSL-Instructions- td5711254.html
githubにあります:
https ://github.com/wpiasecki/glissando