为什么 MissingMethod 不适用于 Closure?

发布于 2024-11-09 04:26:39 字数 261 浏览 0 评论 0原文

更新

我必须为让读者感到困惑而道歉。当我完全迷失在代码中之后,我恢复了 Mercurial 存储库中的所有更改,小心地应用了与以前相同的逻辑——并且它起作用了。下面的答案帮助我更好地理解(对我来说是新的)概念,为此我给了他们赞成票。

底线:如果在闭包内发生对缺失方法的调用,并且解析设置为 DELEGATE_FIRST,则将在委托上调用 methodMissing() 。如果没有——检查你自己的代码,某处有拼写错误。

多谢!

UPDATE

I have to apologize for confusing the readers. After I got totally lost in the code, I reverted all my changes from Mercurial repo, carefully applied the same logic as before -- and it worked. The answers below helped me understand the (new to me) concept better, and for that I gave them upvotes.

Bottom line: if a call to a missing method happens within a closure, and resolution set to DELEGATE_FIRST, methodMissing() will be called on the delegate. If it doesn't -- check you own code, there is a typo somewhere.

Thanks a lot!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

久夏青 2024-11-16 04:26:39

编辑:
好的,现在您已经澄清了您在做什么(有点;--))

另一种方法(我用于 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() ,无论使用什么委托策略,它都会失败;即,如果您不使用(字符串)委托,祝您好运。举个例子,执行 "".foo() 就可以了。

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

Edit:
OK, now that you've clarified what your are doing (somewhat ;--))

Another approach (one that I use for DSLs) is to parse your closure group to map via a ClosureToMap utility like this:

// 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

Now you can iterate through the map, perhaps adding methods to applicable MCL instance. For example, some of my domains have dynamic finders like:

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

I create a map using the ClosureToMap utility, and then iterate through, adding map keys (methods, like "userStatus") and values (in this case, closure "eq") to domain instance MCL, delegating the closure to our ORM, like so:

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

In this way in controller scope I can do, say:

def actives = Orders.userStatusPaid()

and "eq" closure will delegate to the ORM and not domain Orders where an MME would occur.

Play around with it, hopefully I've given you some ideas for how to solve the problem. In Groovy, if you can't do it one way, try another ;--)

Good luck!

Original:
Your missingMethod is defined on string metaclass; in order for it to be invoked, you need "someString".foo()

If you simply call foo() by itself within your closure it will fail, regardless of delegation strategy used; i.e. if you don't use the (String) delegate, good luck. Case in point, do "".foo() and it works.

I don't fully understand the issue either, why will you not have access to the closure's delegate? You are setting the closure's delegate and will invoke the closure, which means you will have access to the delegate within the closure itself (and can just delegate.foo())

各空 2024-11-16 04:26:39

不,您不会捕获丢失的方法并使用元类魔法将其重定向到委托。
闭包委托是捕获这些调用并使它们适应支持域的机会。
这意味着...
您应该使用 dsl 所需的方法创建自己的委托。
如果类不是为该任务而设计的,请不要尝试强制该类执行委托工作,否则代码很快就会变得非常混乱。
将与 dsl 相关的所有内容保留在一组专门设计的委托类中,所有内容都会突然变得异常简单和清晰。

nope, you will not catch a missing method and redirect it to the delegate with metaclass magic.
the closure delegate is the chance to capture those calls and adapt them to the backing domain.
that means...
you should create your own delegate with the methods required by the dsl.
do not try to force a class to do delegate work if it's not designed for the task, or the code will get really messy in not time.
keep everything dsl related in a set of specially designed delegate classes and everything will suddenly become ridiculously simple and clear.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文