Почему пропавший метод не работает для закрытия? - PullRequest
0 голосов
/ 23 мая 2011

ОБНОВЛЕНИЕ

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

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

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

Ответы [ 2 ]

1 голос
/ 24 мая 2011

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

1 голос
/ 23 мая 2011

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

Другой подход (который я использую для 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 ())

...