I tried to add a repeat refinement to build-markup function using the previous answer:
How to bind to foreach context?
build-markup: func [
{Return markup text replacing <%tags%> with their evaluated results.}
content [string! file! url!]
/repeat block-fields block-values
/quiet "Do not show errors in the output."
/local out eval value
][
either not repeat [
content: either string? content [copy content] [read content]
out: make string! 126
eval: func [val /local tmp] [
either error? set/any 'tmp try [do val] [
if not quiet [
tmp: disarm :tmp
append out reform ["***ERROR" tmp/id "in:" val]
]
] [
if not unset? get/any 'tmp [append out :tmp]
]
]
parse/all content [
any [
end break
| "<%" [copy value to "%>" 2 skip | copy value to end] (eval value)
| copy value [to "<%" | to end] (append out value)
]
]
][
probe :block-fields
foreach :block-fields block-values [
print get pick :block-fields 1
print get pick :block-fields 2
]
]
out
]
c: [a b]
template: "<%a%> <%b%>"
build-markup/repeat template :c [1 2 3 4]
Output is not what I want:
>> c: [a b]
== [a b]
>> template: "<%a%> <%b%>"
== "<%a%> <%b%>"
>> build-markup/repeat template :c [1 2 3 4]
[a b]
1
1 a b
1
1 a b
whereas I would have expected
1
2
3
4
So how should I correct ?
For:
words: [num]
vals: [1 2 3]
When you use foreach :words
, you are creating a new context for which the repeat block will be bound to. The word!
contents of :words
are not actually bound to this new context. The values you are getting suggest 'a
is globally set to 1 and 'b
is set to [a b]
. To illustrate:
>> num: 9
== 9
>> words: [num]
== [num]
>> foreach :words vals [
[ probe get 'num
[ probe get first :words
[ ]
1
9
2
9
3
9
== 9
To work around this, try to picture that for each iteration of the loop, the block that is executed is 'bind
-ed to the loop context. You can preempt the bind like this:
foreach :words vals probe compose/only [
probe get first (words)
]
(probe left in for illustrative purposes)
seems to work:
build-markup: func [
{Return markup text replacing <%tags%> with their evaluated results.}
content [string! file! url!]
/repeat block-fields block-values
/quiet "Do not show errors in the output."
/local out eval value
][
out: make string! 126
either not repeat [
content: either string? content [copy content] [read content]
eval: func [val /local tmp] [
either error? set/any 'tmp try [do val] [
if not quiet [
tmp: disarm :tmp
append out reform ["***ERROR" tmp/id "in:" val]
]
] [
if not unset? get/any 'tmp [append out :tmp]
]
]
parse/all content [
any [
end break
| "<%" [copy value to "%>" 2 skip | copy value to end] (eval value)
| copy value [to "<%" | to end] (append out value)
]
]
][
actions: compose/only [
set in system/words (to-lit-word pick (block-fields) 1) get pick (block-fields) 1
set in system/words (to-lit-word pick (block-fields) 2) get pick (block-fields) 2
probe get in system/words (to-lit-word pick (block-fields) 1)
probe get in system/words (to-lit-word pick (block-fields) 2)
append out build-markup content
]
foreach :block-fields block-values actions
]
out
]
template1: { <td><%a%></td><td><%b%></td>
}
template2: { <tr>
<%build-markup/repeat template1 [a b] [1 2 3 4]%>
</tr>
}
template3: {<table>
<%build-markup/repeat template2 [a b] [1 2 3 4 5 6]%>
</table>}
build-markup template3
output:
== {<table>
<tr>
<td>1</td><td>2</td>
<td>3</td><td>4</td>
</tr>
<tr>
<td>1</td><td>2</td>
<td>3</td><td>4</...
>
>