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 просто преобразует неизвестные свойства в строку их имени

Другие вопросы по тегам