Reputation: 187399
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
Upvotes: 5
Views: 4762
Reputation: 486
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[])
}
}
Upvotes: 7
Reputation: 26059
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
}
Upvotes: 1