Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

groovy closure parameters

The following example of using the sendMail method provided by the grails mail plugin appears in this book.

sendMail {
    to "[email protected]"
    subject "Registration Complete"
    body view:"/foo/bar", model:[user:new User()]
}

I understand that the code within {} is a closure that is passed to sendMail as a parameter. I also understand that to, subject and body are method calls.

I'm trying to figure out what the code that implements the sendMail method would look like, and my best guess is something like this:

MailService {

    String subject
    String recipient
    String view
    def model

    sendMail(closure) {
        closure.call()
        // Code to send the mail now that all the 
        // various properties have been set
    }

    to(recipient) {
        this.recipient = recipient
    }

    subject(subject) {
        this.subject = subject;
    }

    body(view, model) {
        this.view = view
        this.model = model
    }
}

Is this reasonable, or am I missing something? In particular, are the methods invokedwithin the closure (to, subject, body), necessarily members of the same class as sendMail?

Thanks, Don

like image 666
Dónal Avatar asked May 18 '09 01:05

Dónal


People also ask

What is a closure in Jules?

A closure is an anonymous block of code.

What is the role of closure and listeners in Groovy?

6) Mention what is the role of closure and listeners in Groovy? Groovy does not support anonymous inner classes; it is possible to determine action listeners inline through the means of closures. In Groovy, listeners closure are used as a ListenerAdapter where only one method of interest is overridden.

What is inject in Groovy?

Inject is the groovy way to do a left fold. Left fold is basically iterating over a list from the head and applying a function to the current element and the accumulated value.


2 Answers

MailService.sendMail closure delegating:

 MailMessage sendMail(Closure callable) {
    def messageBuilder = new MailMessageBuilder(this, mailSender)
    callable.delegate = messageBuilder
    callable.resolveStrategy = Closure.DELEGATE_FIRST
    callable.call()

    def message = messageBuilder.createMessage()
    initMessage(message)
    sendMail message
    return message
}

and for example, the method to at MailMessageBuilder:

void to(recip) {
    if(recip) {
        if (ConfigurationHolder.config.grails.mail.overrideAddress)
            recip = ConfigurationHolder.config.grails.mail.overrideAddress
        getMessage().setTo([recip.toString()] as String[])
    }
}
like image 149
Bruno Fuster Avatar answered Oct 16 '22 08:10

Bruno Fuster


I'm not sure exactly what the sendMail method does as I do not have the book you mention. The sendMail method does indeed take a closure as you describe but it probably uses a builder rather than being executed in the normal way. Essentially that would be a Domain Specific Language for describing an email to be sent.

The reason the class you defined would not work is that the scope of the closure is where it is declared not where it is run. So having your closure call the to() method, it would not be able to call the to method in MailService unless you passed the instance of mail service into the closure.

With a few modifications, your example could work though using a regular closure. The following changes to the call and

// The it-> can be omitted but I put it in here so you can see the parameter
service.sendMail {it->
    it.to "[email protected]"
    it.subject "Registration Complete"
    it.body view:"/foo/bar", model:[user:new User()]
}

The sendMail method in the class should look like this

def sendMail(closure) {
    closure(this)
    // Code to send the mail now that all the 
    // various properties have been set
}
like image 42
Chris Dail Avatar answered Oct 16 '22 09:10

Chris Dail