As another instance of "I want to augment this block as a function body, with some stuff" there's this pattern in HTTPD. Here is a usage:
The idea is that SERVER.SPEC.ACTIONS is a plain BLOCK! of what to do. Here's a sample usage:
import %httpd.reb
trap [
str: {Test} n: 0
wait srv: open [scheme: 'httpd 8000 [
n: n + 1
expected: copy str
repeat n [append expected expected]
lib.print [{SERVER} n {:} (length of as binary! expected) {bytes}]
render expected
]]
] then (func [e] [print mold/limit e 2000])
If you do something like fetch %index.html, that BLOCK! after the 8000 is executed. Here what's happening is it's just incrementing a number and doubling the length of the response sent back each time.
The implementation was like this:
server.locals.handler: func [
return: [~]
request [object!]
response [object!]
] compose [
render: :response.render
redirect: :response.redirect
print: :response.print
(spread (
match block! server.spec.actions else [default-response]
))
]
It wants to override PRINT so that what you print becomes part of the response. So you're supposed to get these three service functions RENDER / REDIRECT / PRINT as well as access to the REQUEST and RESPONSE objects.
Now that SPREAD is spreading unbound material, this does not work.
PUNCH would be one way of doing this:
server.locals.handler: func [
return: [~]
request [object!]
response [object!]
] compose [
render: :response.render
redirect: :response.redirect
print: :response.print
(punch [request response render redirect print] as group! (
match block! server.spec.actions else [default-response]
))
]
Though if you had something like WITH you could imagine it like:
server.locals.handler: func [
return: [~]
request [object!]
response [object!]
] compose [
do with [request response { ; idea of FENCE! representing object
render: :response.render
redirect: :response.redirect
print: :response.print
}] (
match block! server.spec.actions else [default-response]
)
]
The COMPOSE is not strictly necessary there, but it lets you do at least a little work once vs. every time the function is called.
Which points to something useful about the PUNCH-based concept... beyond being usable in dialects where things like DO WITH aren't available... it has the potential to perform better (assuming punch-merges are faster than usermode function calls, which I believe they would be).