DSL与groovy - >将值传递给metaClass方法

时间:2012-08-14 08:26:07

标签: groovy dsl

我正在尝试为某些特定任务编写迷你DSL。为此我一直试图解决下面这样的问题(不使用parantheses):

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

问题是如何在右侧添加更多的元类方法。 E.g。

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"} }

这个metaClass方法就像一样,只有当左边有一个返回值才能应用,对吗?我尝试在左侧的所有闭包中添加一个return语句,但我总是收到

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 是一个闭包,,opts 名为是MetaClass方法(至少这是我的想象), X,A,B,C,Y 是最可能是字符串的参数, FEATURE 是MetaClass属性,或者是没有参数的闭包或带参数的闭包。

如果 FEATURE 不接受参数,那么 add FEATURE 作为参数就足够了,并返回一个值

Object.metaClass.of将使用参数X

执行

Object.metaClass.opts将在返回的OF值上执行,参数为A,B,C

Object.metaClass.named将在带有参数Y

的opts值返回时执行

这些元类方法中的每一个都将其参数设置为map中的值,当调用 named 时,该值将传递给JAVA方法。

我不确定这是解决这个问题的最佳解决方案,但在我看来这一刻。问题是如果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"]

这个地图填写完毕,当解析名为时会发生这种情况,我称之为java方法 setFeature(params.of,params.named,params.opts,params.feature)

在第二种情况下,长度预定义为length =“length”,参数值仅为

params = [feature : length, 
    of: null,
    opts: null,
    named: "LENGTH"]

并且因为是null,将调用另一个java方法,即addSurfaceFeature(params.feature,params.named)。第二种情况或多或少地向前发展,但第一种情况是我无法管理的情况。

提前致谢! IV

1 个答案:

答案 0 :(得分:0)

你可以做这种事情......这会让你接近吗?

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方法只是将未知属性转换为其名称的字符串