DSL с groovy -> передача значений в методы metaClass
Я пытаюсь написать мини DSL для какой-то конкретной задачи. Для этого я пытался решить проблему, подобную этой ниже (без использования паратезов):
give me 5 like romanLetter
give me 5 like word
где первая строка будет возвращать "V", а вторая "пять"
Мои определения для первой части дают мне 5 выглядеть так
def give = { clos -> clos() }
def me = { clos -> [:].withDefault { it
println it}
}
а затем дай мне 5 отпечатков 5
Проблема в том, как добавить больше методов метакласса справа. Например
give me 5 like romanLetter -> prints V OR
give me 5 like word -> prints five
моя интуиция в том, что я определяю как
Object.metaClass.like = {orth -> if (orth.equals("roman")){ println "V"}
else {println "five"} }
этот метод метакласса работает, только если есть возвращаемое значение слева, к которому нужно применить, верно? Я попытался добавить оператор возврата во все замыкания, которые находятся на левой стороне, но я всегда получаю
groovy.lang.MissingPropertyException: No such property: like
for class: com.ontotext.paces.rules.FERulesScriptTest ...
у тебя есть идея, как мне быть?
========================================
Вот приложение того, что я прошу. Я хочу сделать правило следующим
add FEATURE of X opts A,B,C named Y
где add - это замыкание, of, opts и named - это методы MetaClass (по крайней мере, так я это себе представляю), X, A, B, C, Y - это наиболее вероятные строки, а FEATURE - это либо свойство MetaClass, либо замыкание без аргументы или замыкание с аргументами.
Если FEATURE не принимает аргументы, достаточно добавить, что FEATURE является аргументом и возвращает значение, для которого
Object.metaClass.of будет выполняться с параметром X
Object.metaClass.opts будет выполнен для возвращенного значения OF с параметрами A, B, C
Object.metaClass.named будет выполнен для возвращаемого значения opts с параметром Y
каждый из этих методов метакласса устанавливает свой параметр в качестве значения на карте, которая передается методу JAVA при вызове named.
Я не уверен, что это лучшее решение для такой проблемы, но мне пока кажется, что так оно и есть. Проблема в том, что FEATURE - это не само свойство, а замыкание, которое принимает аргумент (например, feature1 ARG1). затем
add feature1 ARG1 of X opts A,B,C named Y
и это тот случай, с которым я застрял. добавь feature1 ARG1 - это часть 5, и я пытаюсь добавить к ней остальное.
================================================== ======
ПРИМЕРЫ: мне нужно, чтобы оба следующих работали:
add contextFeature "text" of 1,2,3 opts "upperCase" named "TO_UPPER"
add length named "LENGTH"
где в первом случае путем анализа правила всякий раз, когда вызывается каждый метод метакласса , opts, named, я заполняю соответствующее значение в следующей карте:
params = [feature: "text",
of: 1,2,3,
opts: "upperCase",
named: "TO_UPPER"]
те, которые заполнены этой картой, что происходит, когда named анализируется, я вызываю java-метод setFeature(params.of, params.named, params.opts, params.feature)
Во втором случае длина предопределена как длина = "длина", значения параметров будут только
params = [feature : length,
of: null,
opts: null,
named: "LENGTH"]
и поскольку значение равно null, будет вызван другой java-метод, который называется addSurfaceFeature(params.feature, params.named). Второй случай более или менее прямой, но первый - тот, с которым я не могу справиться.
Заранее спасибо! Iv
1 ответ
Вы можете делать такие вещи... Это близко к вам?
def contextFeature( type ) {
"FEATURE_$type"
}
// Testing
new IvitaParser().parse {
a = add text of 1,2,3 opts "upperCase" named "TO_UPPER"
b = add length named "LENGTH"
c = add contextFeature( "text" ) of 1,2,3 opts "upperCase" named "TO_UPPER"
}
assert a == [feature:'text', of:[1, 2, 3], opts:'upperCase', named:'TO_UPPER']
assert b == [feature:'length', of:null, opts:null, named:'LENGTH']
assert c == [feature:'FEATURE_text', of:[1, 2, 3], opts:'upperCase', named:'TO_UPPER']
// Implementation
class IvitaParser {
Map result
def parse( Closure c ) {
c.delegate = this
c.resolveMethod = Closure.DELEGATE_FIRST
c()
}
def propertyMissing( String name ) {
name
}
def add( String param ) {
result = [ feature:param, of:null, opts:null, named:null ]
this
}
def of( Object... values ) {
result.of = values
this
}
def named( String name ) {
result.named = name
result
}
def opts( String opt ) {
result.opts = opt
this
}
}
Вы даже можете избавиться от кавычек в определении:
a = add text of 1,2,3 opts upperCase named TO_UPPER
b = add length named LENGTH
Поскольку метод propertyMissing просто преобразует неизвестные свойства в строку их имени