Почему пропавший метод не работает для закрытия?

ОБНОВИТЬ

Я должен извиниться за то, что запутал читателей. После того, как я полностью потерялся в коде, я отменил все свои изменения в репозитории Mercurial, осторожно применил ту же логику, что и раньше - и это сработало. Приведенные ниже ответы помогли мне лучше понять (новую для меня) концепцию, и за это я высказал им свои голоса.

Итог: если в закрытии происходит вызов отсутствующего метода, а для разрешения установлено значение DELEGATE_FIRST, метод делегата будет вызывать метод Missing(). Если это не так - проверьте свой код, где-то есть опечатка.

Большое спасибо!

2 ответа

Решение

Изменить: ОК, теперь, когда вы пояснили, что вы делаете (немного;-))

Другой подход (который я использую для 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") и значения (в данном случае, closure "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())

Нет, вы не поймаете отсутствующий метод и не перенаправите его делегату с помощью волшебства метакласса.
закрывающий делегат - это возможность перехватить эти вызовы и адаптировать их к резервному домену.
это означает...
Вы должны создать свой собственный делегат с методами, необходимыми для DSL.
не пытайтесь заставить класс выполнять делегатскую работу, если он не предназначен для этой задачи, или код станет очень запутанным за короткое время.
храните все, что связано с dsl, в наборе специально разработанных классов делегатов, и все внезапно станет смехотворно простым и понятным.

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