// closures_advanced.groovy — owner, delegate, currying, composition, memoize, trampoline. // 1. this, owner and delegate class Report { String title = 'Daily report' def build() { def c = { "title from owner: $title" } // resolves to the enclosing object c() } } println new Report().build() // 2. Delegates power Groovy DSLs (Gradle, Jenkins pipelines, builders) class Email { String to, subject, body def to(String v) { to = v } def subject(String v) { subject = v } def body(String v) { body = v } } def email(Closure spec) { def e = new Email() spec.delegate = e // calls inside the closure go to e spec.resolveStrategy = Closure.DELEGATE_FIRST spec() e } def mail = email { to 'ops@example.test' subject 'Integration failed' body '3 records rejected' } println "${mail.to} | ${mail.subject} | ${mail.body}" // 3. Currying: fix some arguments now, the rest later def price = { taxRate, amount -> amount * (1 + taxRate) } def withUkVat = price.curry(0.20) // taxRate fixed def withIndiaGst = price.curry(0.18) println withUkVat(100) // 120.00 println withIndiaGst(100) // 118.00 def subtract = { a, b -> a - b } println subtract.rcurry(1)(10) // fixes the LAST argument: 9 // 4. Composition: chain closures with >> and << def trim = { it.trim() } def upper = { it.toUpperCase() } def tag = { "<$it>" } def clean = trim >> upper >> tag // left to right println clean(' po-4471 ') // println((tag << upper)('acme')) // right to left: // 5. Memoize: cache results of an expensive closure def calls = 0 def slowLookup = { String sku -> calls++; sleep 50; sku.reverse() }.memoize() 3.times { slowLookup('AX-200') } println "lookup ran $calls time(s)" // 1 // 6. Trampoline: deep recursion without StackOverflowError def sumTo sumTo = { long n, long acc = 0 -> n == 0 ? acc : sumTo.trampoline(n - 1, acc + n) }.trampoline() println sumTo(100_000) // 5000050000 // 7. Closure parameters and the 'with' / 'tap' helpers def order = [id: 'PO-1', lines: []].tap { it.lines << 'AX-200' } println order println 'boomi'.with { it.capitalize() + ' rocks' } println "maximumNumberOfParameters: ${price.maximumNumberOfParameters}"