2013-08-27 1 views
2

Мне интересно, как вызывать замыкание из крышки, которая используется с DSL. Например, давайте возьмем плагин RestBuilder для Grails.Groovy/Grails: Как составить закрытие без разрыва DSL

Представьте У меня есть несколько блоков в ряд, как:

rest.post("http://my.domain/url") { 
    auth(username, password) 
    contentType "text/xml" 
    body someContent 
} 

... где единственное изменение является someContent. Периодически звонит auth и contentType и body каждый раз. Так что я хотел бы сделать что-то вроде:

def oauth = [clientId: 'c', clientSecret: 's'] 

def withAuth(Closure toWrap) { 
    Closure wrapped = { it -> 
     auth(oauth.clientId, oauth.clientSecret) 
     contentType "text/xml" 
     toWrap.call() 
    } 
    return wrapped 
} 

rest.post("http://my.domain/url") (withAuth { 
    body someContent 
}) 

Теперь я хотел бы wrapped и toWrap, чтобы иметь доступ к auth и contentType, как определено в RestBuilder DSL. Есть ли способ сделать это, установив владельцев, делегатов или так далее?

(Примечание: в приведенном выше примере я понимаю, что я могу просто объявить функцию, которая принимает контент URL + в качестве аргумента, и просто вызовет rest.post внутри функции. Мой вопрос более общий - я хочу понять языка и функциональных методов можно применять в более широком смысле)

+1

Вероятно, установить 'делегат' будет достаточно:' toWrap.delegate = delegate; toWrap.call() ' –

+0

Это не совсем трюк, потому что, когда он вызывается, код в' wrapped' не может видеть oauth в верхней области. – Bosh

+0

А, я вижу, мне нужно определить 'oauth' как @Field в моем скрипте (http://stackoverflow.com/questions/6305910/how-do-we-create-and-access-the-global-variables- in-groovy) – Bosh

ответ

1

Вы можете воспользоваться тем, что синтаксис там из foo(params) { ... } является синтаксически foo(params, { ... }):.

def c = { oauth, b -> 
    auth(oauth.clientId, oauth.clientSecret) 
    contentType "text/xml" 
    body b 
} 

... 

def doPost(String body) { 
    rest.post("http://my.domain/url", c.clone().curry(oauth, body)) 
} 

Клонирование Замыкание каждый раз предотвращает устаревшее состояние и вычисление значений кэширует их в закрытии, поэтому они доступны, когда он вызывается создателем Rest.

+0

Это отличный синтаксис для понимания, но он не совсем понимает, как я могу составить замыкания: в этом случае вы передаете одно замыкание на 'rest.post' (и что закрытие, возвращенное 'curry', не запускает никаких закрытий внутри). – Bosh

1

Благодаря @ igor-artamonov, у меня есть следующий рабочий подход. Обратите внимание, что я изменил withAuth от функции к закрытию, чтобы он мог получить доступ к состоянию на уровне скрипта без объявления переменных @Field в скрипте.

def oauth = [clientId: 'c', clientSecret: 's'] 

def withAuth { Closure toWrap -> 
    return { 
     auth(oauth.clientId, oauth.clientSecret) 
     contentType "text/xml" 
     toWrap.delegate = delegate 
     toWrap.call() 
    } 
} 

rest.post("http://my.domain/url", withAuth { 
    body someContent 
})