Почему пропавший метод не работает для закрытия?
ОБНОВИТЬ
Я должен извиниться за то, что запутал читателей. После того, как я полностью потерялся в коде, я отменил все свои изменения в репозитории 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, в наборе специально разработанных классов делегатов, и все внезапно станет смехотворно простым и понятным.