malc
malc

Reputation: 147

Closures in a multiline string

I am not sure if it is even possible, but I wish to add a closure with a loop in a multiline string that would generate another multiline string at each loop.

 String body = """\
    Total Invoice Amount: £${totalInvAmt}

    ${quantities.each { qty ->
        Offer offer = Offer.findByShoppingItem(qty.shoppingItem)
        def itemDetails = """\
            Name: ${offer.itemName}
            Qty: $qty.value"""

        itemDetails
    }}
    """

The closure will loop over a list of items and for each item concatenate an multistring. All this produces is

Total Invoice Amount: £1100

    [100, 100]

Thanks in advance for any help

Upvotes: 2

Views: 2065

Answers (2)

Jeff Scott Brown
Jeff Scott Brown

Reputation: 27220

You could use a template engine.

import groovy.text.GStringTemplateEngine

def music = [:]
music.Riverside = ['Second Life Syndrome', 'Anno Domini High Definition']
music.Beardfish = ['Destined Solitare', 'Mammoth']

def templateText = '''
Number Of Artists: ${music.size()}.

<% music.each { artist, albums -> %>\
Artist Name: ${artist}
    <% albums.each { albumTitle -> %>\
    Album Title: ${albumTitle}
    <% } %>
<% } %>
'''

def engine = new GStringTemplateEngine()
def template = engine.createTemplate(templateText).make(music:music)

println template.toString()

That will produce output like this:

Number Of Artists: 2.

Artist Name: Riverside  
    Album Title: Second Life Syndrome    
    Album Title: Anno Domini High Definition    

Artist Name: Beardfish    
    Album Title: Destined Solitare    
    Album Title: Mammoth    

You have a number of options and a good bit of flexibility in how you put that together. See http://beta.groovy-lang.org/templating.html for more info.

I hope that helps.

Upvotes: 0

Dave Newton
Dave Newton

Reputation: 160191

Here's pseudo-code that does something closer to what you want, delta I'm not going to try to reproduce your data structs etc. without an SSCCE.

Nutshell: each iterates, you want to collect.

body = """
    Total Invoice Amount: £${totalInvAmt}

    ${quantities.collect { qty ->
        offer = Offer.findByShoppingItem(qty.shoppingItem)
        """
            Name: ${offer.itemName}
            Qty: ${qty.value}
        """
    }.join('\n')}
"""

I'd urge you never to do anything like this; it's abusive. At a minimum the inner string generation should be handled in its own method, not wedged in the middle of another string. It's difficult to read and maintain.

Upvotes: 1

Related Questions