为什么missingMethod不适用于Closure?

时间:2011-05-23 13:17:48

标签: groovy closures missingmethod

更新

我要为混淆读者而道歉。在我完全迷失在代码中之后,我从Mercurial repo中恢复了所有更改,仔细应用了与以前相同的逻辑 - 并且它有效。下面的答案帮助我更好地理解(对我来说是新的)概念,为此我给了他们赞成票。

底线:如果在闭包内发生对缺失方法的调用,并且将分辨率设置为DELEGATE_FIRST,则将在委托上调用methodMissing()。如果没有 - 检查你自己的代码,那么在某处就会出现错字。

非常感谢!

2 个答案:

答案 0 :(得分:1)

修改 好了,既然你已经澄清了你在做什么(有点; - ))

另一种方法(我用于DSL的方法)是解析你的闭包组,通过像这样的ClosureToMap实用程序进行映射:

// converts given closure to map method => value pairs (1-d, if you need nested, ask)
class ClosureToMap {
    Map map = [:]
    ClosureToMap(Closure c) {
        c.delegate = this
        c.resolveStrategy = Closure.DELEGATE_FIRST
        c.each{"$it"()}
    }
    def methodMissing(String name, args) {
        if(!args.size()) return
        map[name] = args[0]
    }
    def propertyMissing(String name) { name }
}

// Pass your closure to the utility and access the generated map
Map map = new ClosureToMap(your-closure-here)?.map

现在,您可以遍历地图,也许可以向适用的MCL实例添加方法。例如,我的一些域名具有动态查找器,如:

def finders = {
    userStatusPaid = { Boolean active = true->
        eq {
            active    "$active"
            paid      true
        }
    }
}

我使用ClosureToMap实用程序创建一个映射,然后迭代,将映射键(方法,如“userStatus”)和值(在本例中为闭包“eq”)添加到域实例MCL,将闭包委托给我们ORM,就像这样:

def injectFinders(Object instance) {
    if(instance.hasProperty('finders')) {
        Map m = ClosureToMap.new(instance.finders).map
        m?.each{ String method, Closure cl->
            cl.delegate = instance.orm
            cl.resolveStrategy = Closure.DELEGATE_FIRST
            instance.orm.metaClass."$method" = cl
        }
    }
}

这样在控制器范围内,我可以这么做,比如说:

def actives = Orders.userStatusPaid()

和“eq”闭包将委托给ORM,而不是MME发生的域名订单。

玩弄它,希望我已经给你一些如何解决问题的想法。在Groovy中,如果你不能单向执行,请尝试另一种方法; - )

祝你好运!

<强>原始 您的missingMethod是在字符串元类上定义的;为了调用它,你需要“someString”.foo()

如果您只是在闭包中单独调用foo(),它将失败,无论使用何种委派策略;即如果你不使用(String)委托,祝你好运。例如,做“”.foo()并且它有效。

我也不完全理解这个问题,你为什么不能访问闭包的代表呢?您正在设置闭包的委托并将调用闭包,这意味着您将可以访问闭包本身内的委托(并且可以只委托.foo())

答案 1 :(得分:1)

nope,你不会捕获一个丢失的方法并将其重定向到具有元类魔法的委托 封闭代表是 抓住这些调用并将其调整到支持域的机会 这意味着......
您应该使用dsl所需的方法创建自己的委托 如果不是为任务设计的话,不要试图强迫某个类进行委托工作,否则代码会在非时间内变得非常混乱。
在一组专门设计的委托类中保留所有与dsl相关的内容,一切都会突然变得荒谬简单明了。