Replacing placeholders?
[1/11] from: kpeters:otaksoft at: 7-Aug-2007 11:30
Hi ~
I am trying to use pdfmaker to perform a mail-merge mailout.
I have created a file holding the dialect code for the letter template:
thankyou-letter: [
[ ; the one & only page
page size 216 279 ; US letter
textbox [
{ Dear $NAME, thank you so much for your generous donation.} p
{ And some more text - maybe the same placeholder multiple times $NAME ...}
]
]
]
All this up to creating the PDF works well.
I am struggling with this:
How can i replace all instances of placeholders like $NAME in thankyou-letter with the
mailmerge variables?
Thanks for any help,
Kai
[2/11] from: carlos:lorenz:g:mail at: 7-Aug-2007 15:46
Hi Kai,
Maybe this old mail from Tim may help you. Take a look:
>>>
Here's an example of dynamically composing a PDF document
using records:
;; ======================================================
do %pdf-maker.r
records: [
[first_name "Tim" last_name "Johnson"]
[first_name "Gabriele" last_name "Santilli"]
]
build-page: func[record[block!]][
blue-font: [FONT Courier 4.23 0.0.200]
black-font: [FONT Helvetica 4.23 0.0.0]
;; Place any code that you want evaluated inside of parenthesis
[ ;; Each page must be a block
textbox[
LEFT ALIGN
(blue-font) "First Name: "
(black-font) (record/first_name) newline
(blue-font) "Last Name: "
(black-font) (record/last_name) newline
]
]
]
;; make block for the document
document: make block! length? records
;; Process records
foreach record records[
;; Use 'compose to evaluate the code and data
;; inside of the parens in the 'page block
page: compose/deep build-page record
;; append as a block
append/only document page
]
write/binary %pdf-test.pdf layout-pdf document
;; ======================================================
It's my hope that someone else may find this as helpful
as it was for me in doing it.
And as always - thanks to Gabrielle for his good work.
cheers
Tim
>>>>>
2007/8/7, Kai Peters <kpeters-otaksoft.com>:
> Hi ~
> I am trying to use pdfmaker to perform a mail-merge mailout.
<<quoted lines omitted: 19>>
> To unsubscribe from the list, just send an email to
> lists at rebol.com with unsubscribe as the subject.
--
Carlos Lorenz
www.revistaeletronica.com.br
Unidade Lorenz Ltda
(11) 4034 1971
[3/11] from: kpeters::otaksoft::com at: 7-Aug-2007 12:53
Carlos ~
thank you so much for this - this would have been the next step for me
to wrestle with!
Now that I have seen this code, my ultimate goal is to be able to
do this:
Have the actual "page content" made "load"able from an external file
In Tim's code this would be this section (I believe):
textbox[
LEFT ALIGN
(blue-font) "First Name: "
(black-font) (record/first_name) newline
(blue-font) "Last Name: "
(black-font) (record/last_name) newline
]
}
and pass it on to build-page as an additional parameter. This
should add a lot of flexibility as it separates the actual PDF
definitions from the code.
I have just tried in vain to achieve this as I somehow always
end up with empty PDFs or worse....
Would you be able to advise me once more?
TIA,
Kai
[4/11] from: carlos:lorenz:gm:ail at: 8-Aug-2007 15:15
Kai,
I am afraid a cannot go further on advising you since I am not a heavy user
of pdf-maker.
Anyway are you using COMPOSE to evaluate data and surrounding them with
parens as Tim said?
>> Timīs code
;; Process records
foreach record records[
;; Use 'compose to evaluate the code and data
;; inside of the parens in the 'page block
page: compose/deep build-page record
;; append as a block
append/only document page
]
2007/8/7, Kai Peters <kpeters-otaksoft.com>:
> Carlos ~
> thank you so much for this - this would have been the next step for me
<<quoted lines omitted: 22>>
> To unsubscribe from the list, just send an email to
> lists at rebol.com with unsubscribe as the subject.
--
Carlos Lorenz
www.revistaeletronica.com.br
Unidade Lorenz Ltda
(11) 4034 1971
[5/11] from: tim-johnsons::web::com at: 8-Aug-2007 12:15
On Wednesday 08 August 2007, Carlos Lorenz wrote:
> Kai,
>
> I am afraid a cannot go further on advising you since I am not a heavy user
> of pdf-maker.
> Anyway are you using COMPOSE to evaluate data and surrounding them with
> parens as Tim said?
<blush> I've been extremely busy here and I've got a little time for this -
first - a disclaimer - I whipped up that code in preperation for
implementing it for a client. But my partner ended doing the functionality
with perl. Furthermore, I've deleted much of *this* thread from my mailer.
Let me suggest that you just play with compose for a bit, without your
target in mind. Just a have a bit of fun with it. What compose allows you to
do is to create a data structure, evaluate it as much as you like and
change values within that data structure targeted by parenthesis.
Since I am not myself an expert with compose, and if I don't write rebol for
a week, I get behind the curve even more, let me propose a problem and
perhaps the solution will edify me and help you:
Here's the problem, define a block with a parenthesized word and evaluate it
as a place holder
names: ["Tim" "Carlos" "Kai"]
== ["Tim" "Carlos" "Kai"]
>> template: [My name is (name)]
== [My name is (name)]
>> foreach name names[print compose template]
** Script Error: name has no value
** Near: name
;; I *don't* know the solution myself, but finding it will be most helpful for
;; both of us
cheers
tim
[6/11] from: tim-johnsons:web at: 8-Aug-2007 13:03
On Wednesday 08 August 2007, Tim Johnson wrote:
> Here's the problem, define a block with a parenthesized word and evaluate
> it as a place holder
<<quoted lines omitted: 7>>
> ;; I *don't* know the solution myself, but finding it will be most helpful
> for ;; both of us
:-) Oh, I couldn't help myself:
solution is:
>> foreach name names[bind template 'name print form compose template]
My name is Tim
My name is Carlos
My name is Kai
----
Tim
[7/11] from: kpeters:otaksoft at: 8-Aug-2007 14:14
Thanks for that one - no way that this newbie here would have figured this
out anytime soon...
If that's what you refer to as "getting behind the curve.." you must be
fishing for compliments :)
Well, at least I learned one little (unrelated) detail from your exercise:
Having a word previously defined with the same name as the implicit loop variable
overshadows the loop variable (forgive me if this terminology is not Rebol proper)
Kai
On Wed, 8 Aug 2007 13:03:18 -0800, Tim Johnson wrote:
[8/11] from: tim-johnsons:web at: 8-Aug-2007 15:09
On Wednesday 08 August 2007, Kai Peters wrote:
> Thanks for that one - no way that this newbie here would have figured this
> out anytime soon...
>
> If that's what you refer to as "getting behind the curve.." you must be
> fishing for compliments :)
No. I code in several languages. When I get away from rebol for a while,
my "reb-Q" drops.
> Well, at least I learned one little (unrelated) detail from your exercise:
>
> Having a word previously defined with the same name as the implicit loop
> variable
> overshadows the loop variable (forgive me if this terminology is not Rebol
> proper)
There is a term called "shadowing" - used in scheme and lisp, but:
see this:
>> names
== ["Tim" "Carlos" "Kai"]
>> key: "George"
== "George"
>> foreach key names[print key]
Tim
Carlos
Kai
>> key
== "George"
;; 'key has scope local to the 'foreach loop,
;; no shadowing here.
Tim
[9/11] from: Tom:Conlin:gmai:l at: 8-Aug-2007 18:36
Tim Johnson wrote:
> On Wednesday 08 August 2007, Carlos Lorenz wrote:
>> Kai,
<<quoted lines omitted: 27>>
> cheers
> tim
names: ["Tim" "Carlos" "Kai"]
template: [My name is (first names)]
while[not tail? names][probe compose template names: next names]
[My name is "Tim"]
[My name is "Carlos"]
[My name is "Kai"]
== []
names: head names
while[not tail? names][print form compose template names: next names]
My name is Tim
My name is Carlos
My name is Kai
== []
>>
[10/11] from: kpeters:otaksoft at: 8-Aug-2007 21:11
Tim ~
my "overshadowing" assumption was wrongly based on output below
Kai
>> names: [ "tim" "carlos" "kai" ]
== ["tim" "carlos" "kai"]
>> template: [ "My name is " (name) ]
== ["My name is " (name)]
>> foreach name names [ print compose template ]
** Script Error: name has no value
** Where: halt-view
** Near: name
>>
>>
>> name: "Joe"
== "Joe"
>> foreach name names [ print compose template ]
My name is Joe
My name is Joe
My name is Joe
>>
On Wed, 8 Aug 2007 15:09:33 -0800, Tim Johnson wrote:
[11/11] from: tim-johnsons:web at: 9-Aug-2007 12:07
On Wednesday 08 August 2007, Kai Peters wrote:
> Tim ~
>
> my "overshadowing" assumption was wrongly based on output below
>
Rebol's approach to scope can be problematic, especially in large
applications.
Example:
;; global value (not inside of a function)
username: "Kai" ;; used for all kinds of things in large application
scopekiller: func[uname[string!] /local user][
username: uname ;; OOPS! typo with unpredicable consequences
]
scopekiller "Tim"
;; username is now me :-)
This is where 'protect can be your friend.
username: "Kai"
protect 'username
and:
;;use 'unprotect before resetting a 'protect'ed global word.
unprotect 'username
username: "Tim"
;;;;;;;;;;;;;;
I also use global words as part of an object, this has a tendency
to lessen typos.
glbs: context[unsername: "Kai"]
glbs/username: "Tim"
tim
Notes
- Quoted lines have been omitted from some messages.
View the message alone to see the lines that have been omitted