updates to docs (including third tutorial)

pull/27/head
Matthew Butterick 10 years ago
parent b92a20378b
commit 8341d2660b

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1,4 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"/><title>1&nbsp;Installation</title><link rel="stylesheet" type="text/css" href="scribble.css" title="default"/><link rel="stylesheet" type="text/css" href="manual-style.css" title="default"/><link rel="stylesheet" type="text/css" href="manual-racket.css" title="default"/><script type="text/javascript" src="scribble-common.js"></script><script type="text/javascript" src="manual-racket.js"></script><!--[if IE 6]><style type="text/css">.SIEHidden { overflow: hidden; }</style><![endif]--></head><body id="scribble-racket-lang-org"><div class="tocset"><div class="tocview"><div class="tocviewlist tocviewlisttopspace"><div class="tocviewtitle"><table cellspacing="0" cellpadding="0"><tr><td style="width: 1em;"><a href="javascript:void(0);" title="Expand/Collapse" class="tocviewtoggle" onclick="TocviewToggle(this,&quot;tocview_0&quot;);">&#9660;</a></td><td></td><td><a href="index.html" class="tocviewlink" data-pltdoc="x">Pollen:<span class="mywbr"> &nbsp;</span> the book is a program</a></td></tr></table></div><div class="tocviewsublistonly" style="display: block;" id="tocview_0"><table cellspacing="0" cellpadding="0"><tr><td align="right">1&nbsp;</td><td><a href="Installation.html" class="tocviewselflink" data-pltdoc="x">Installation</a></td></tr><tr><td align="right">2&nbsp;</td><td><a href="quick-tour.html" class="tocviewlink" data-pltdoc="x">Quick tour</a></td></tr><tr><td align="right">3&nbsp;</td><td><a href="Backstory.html" class="tocviewlink" data-pltdoc="x">Backstory</a></td></tr><tr><td align="right">4&nbsp;</td><td><a href="big-picture.html" class="tocviewlink" data-pltdoc="x">The big picture</a></td></tr><tr><td align="right">5&nbsp;</td><td><a href="first-tutorial.html" class="tocviewlink" data-pltdoc="x">First tutorial</a></td></tr><tr><td align="right">6&nbsp;</td><td><a href="second-tutorial.html" class="tocviewlink" data-pltdoc="x">Second tutorial</a></td></tr><tr><td align="right">7&nbsp;</td><td><a href="raco-pollen.html" class="tocviewlink" data-pltdoc="x">Using <span class="stt">raco pollen</span></a></td></tr><tr><td align="right">8&nbsp;</td><td><a href="File_formats.html" class="tocviewlink" data-pltdoc="x">File formats</a></td></tr><tr><td align="right">9&nbsp;</td><td><a href="reader.html" class="tocviewlink" data-pltdoc="x">&#9674; command overview</a></td></tr><tr><td align="right">10&nbsp;</td><td><a href="Module_reference.html" class="tocviewlink" data-pltdoc="x">Module reference</a></td></tr><tr><td align="right">11&nbsp;</td><td><a href="Acknowledgments.html" class="tocviewlink" data-pltdoc="x">Acknowledgments</a></td></tr><tr><td align="right">12&nbsp;</td><td><a href="License___source_code.html" class="tocviewlink" data-pltdoc="x">License &amp; source code</a></td></tr><tr><td align="right"></td><td><a href="doc-index.html" class="tocviewlink" data-pltdoc="x">Index</a></td></tr></table></div></div></div></div><div class="maincolumn"><div class="main"><div class="versionbox"><span class="version">6.1.0.5</span></div><div class="navsettop"><span class="navleft"><div class="nosearchform"></div>&nbsp;&nbsp;</span><span class="navright">&nbsp;&nbsp;<a href="index.html" title="backward to &quot;Pollen: the book is a program&quot;" data-pltdoc="x">&larr; prev</a>&nbsp;&nbsp;<a href="index.html" title="up to &quot;Pollen: the book is a program&quot;" data-pltdoc="x">up</a>&nbsp;&nbsp;<a href="quick-tour.html" title="forward to &quot;2 Quick tour&quot;" data-pltdoc="x">next &rarr;</a></span>&nbsp;</div><h3>1<tt>&nbsp;</tt><a name="(part._.Installation)"></a>Installation</h3><p><a href="http://download.racket-lang.org/">Install Racket</a>, which includes DrRacket.</p><p><div class="SIntrapara">From the command line, install Pollen:
<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"/><title>1&nbsp;Installation</title><link rel="stylesheet" type="text/css" href="scribble.css" title="default"/><link rel="stylesheet" type="text/css" href="manual-style.css" title="default"/><link rel="stylesheet" type="text/css" href="manual-racket.css" title="default"/><script type="text/javascript" src="scribble-common.js"></script><script type="text/javascript" src="manual-racket.js"></script><!--[if IE 6]><style type="text/css">.SIEHidden { overflow: hidden; }</style><![endif]--></head><body id="scribble-racket-lang-org"><div class="tocset"><div class="tocview"><div class="tocviewlist tocviewlisttopspace"><div class="tocviewtitle"><table cellspacing="0" cellpadding="0"><tr><td style="width: 1em;"><a href="javascript:void(0);" title="Expand/Collapse" class="tocviewtoggle" onclick="TocviewToggle(this,&quot;tocview_0&quot;);">&#9660;</a></td><td></td><td><a href="index.html" class="tocviewlink" data-pltdoc="x">Pollen:<span class="mywbr"> &nbsp;</span> the book is a program</a></td></tr></table></div><div class="tocviewsublistonly" style="display: block;" id="tocview_0"><table cellspacing="0" cellpadding="0"><tr><td align="right">1&nbsp;</td><td><a href="Installation.html" class="tocviewselflink" data-pltdoc="x">Installation</a></td></tr><tr><td align="right">2&nbsp;</td><td><a href="quick-tour.html" class="tocviewlink" data-pltdoc="x">Quick tour</a></td></tr><tr><td align="right">3&nbsp;</td><td><a href="Backstory.html" class="tocviewlink" data-pltdoc="x">Backstory</a></td></tr><tr><td align="right">4&nbsp;</td><td><a href="big-picture.html" class="tocviewlink" data-pltdoc="x">The big picture</a></td></tr><tr><td align="right">5&nbsp;</td><td><a href="first-tutorial.html" class="tocviewlink" data-pltdoc="x">First tutorial</a></td></tr><tr><td align="right">6&nbsp;</td><td><a href="second-tutorial.html" class="tocviewlink" data-pltdoc="x">Second tutorial</a></td></tr><tr><td align="right">7&nbsp;</td><td><a href="third-tutorial.html" class="tocviewlink" data-pltdoc="x">Third tutorial</a></td></tr><tr><td align="right">8&nbsp;</td><td><a href="raco-pollen.html" class="tocviewlink" data-pltdoc="x">Using <span class="stt">raco pollen</span></a></td></tr><tr><td align="right">9&nbsp;</td><td><a href="File_formats.html" class="tocviewlink" data-pltdoc="x">File formats</a></td></tr><tr><td align="right">10&nbsp;</td><td><a href="reader.html" class="tocviewlink" data-pltdoc="x">&#9674; command overview</a></td></tr><tr><td align="right">11&nbsp;</td><td><a href="Module_reference.html" class="tocviewlink" data-pltdoc="x">Module reference</a></td></tr><tr><td align="right">12&nbsp;</td><td><a href="Acknowledgments.html" class="tocviewlink" data-pltdoc="x">Acknowledgments</a></td></tr><tr><td align="right">13&nbsp;</td><td><a href="License___source_code.html" class="tocviewlink" data-pltdoc="x">License &amp; source code</a></td></tr><tr><td align="right"></td><td><a href="doc-index.html" class="tocviewlink" data-pltdoc="x">Index</a></td></tr></table></div></div></div></div><div class="maincolumn"><div class="main"><div class="versionbox"><span class="version">6.1.0.5</span></div><div class="navsettop"><span class="navleft"><div class="nosearchform"></div>&nbsp;&nbsp;</span><span class="navright">&nbsp;&nbsp;<a href="index.html" title="backward to &quot;Pollen: the book is a program&quot;" data-pltdoc="x">&larr; prev</a>&nbsp;&nbsp;<a href="index.html" title="up to &quot;Pollen: the book is a program&quot;" data-pltdoc="x">up</a>&nbsp;&nbsp;<a href="quick-tour.html" title="forward to &quot;2 Quick tour&quot;" data-pltdoc="x">next &rarr;</a></span>&nbsp;</div><h3>1<tt>&nbsp;</tt><a name="(part._.Installation)"></a>Installation</h3><p><a href="http://download.racket-lang.org/">Install Racket</a>, which includes DrRacket.</p><p><div class="SIntrapara">From the command line, install Pollen:
</div><div class="SIntrapara"><table cellspacing="0" cellpadding="0"><tr><td><p><span class="stt">raco pkg install pollen</span></p></td></tr></table></div></p><p><div class="SIntrapara">After that, you can update the package from the command line:
</div><div class="SIntrapara"><table cellspacing="0" cellpadding="0"><tr><td><p><span class="stt">raco pkg update pollen</span></p></td></tr></table></div></p><div class="navsetbottom"><span class="navleft"><div class="nosearchform"></div>&nbsp;&nbsp;</span><span class="navright">&nbsp;&nbsp;<a href="index.html" title="backward to &quot;Pollen: the book is a program&quot;" data-pltdoc="x">&larr; prev</a>&nbsp;&nbsp;<a href="index.html" title="up to &quot;Pollen: the book is a program&quot;" data-pltdoc="x">up</a>&nbsp;&nbsp;<a href="quick-tour.html" title="forward to &quot;2 Quick tour&quot;" data-pltdoc="x">next &rarr;</a></span>&nbsp;</div></div></div><div id="contextindicator">&nbsp;</div></body></html>

@ -1,2 +1,2 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"/><title>12&nbsp;License &amp; source code</title><link rel="stylesheet" type="text/css" href="scribble.css" title="default"/><link rel="stylesheet" type="text/css" href="manual-style.css" title="default"/><link rel="stylesheet" type="text/css" href="manual-racket.css" title="default"/><script type="text/javascript" src="scribble-common.js"></script><script type="text/javascript" src="manual-racket.js"></script><!--[if IE 6]><style type="text/css">.SIEHidden { overflow: hidden; }</style><![endif]--></head><body id="scribble-racket-lang-org"><div class="tocset"><div class="tocview"><div class="tocviewlist tocviewlisttopspace"><div class="tocviewtitle"><table cellspacing="0" cellpadding="0"><tr><td style="width: 1em;"><a href="javascript:void(0);" title="Expand/Collapse" class="tocviewtoggle" onclick="TocviewToggle(this,&quot;tocview_0&quot;);">&#9660;</a></td><td></td><td><a href="index.html" class="tocviewlink" data-pltdoc="x">Pollen:<span class="mywbr"> &nbsp;</span> the book is a program</a></td></tr></table></div><div class="tocviewsublistonly" style="display: block;" id="tocview_0"><table cellspacing="0" cellpadding="0"><tr><td align="right">1&nbsp;</td><td><a href="Installation.html" class="tocviewlink" data-pltdoc="x">Installation</a></td></tr><tr><td align="right">2&nbsp;</td><td><a href="quick-tour.html" class="tocviewlink" data-pltdoc="x">Quick tour</a></td></tr><tr><td align="right">3&nbsp;</td><td><a href="Backstory.html" class="tocviewlink" data-pltdoc="x">Backstory</a></td></tr><tr><td align="right">4&nbsp;</td><td><a href="big-picture.html" class="tocviewlink" data-pltdoc="x">The big picture</a></td></tr><tr><td align="right">5&nbsp;</td><td><a href="first-tutorial.html" class="tocviewlink" data-pltdoc="x">First tutorial</a></td></tr><tr><td align="right">6&nbsp;</td><td><a href="second-tutorial.html" class="tocviewlink" data-pltdoc="x">Second tutorial</a></td></tr><tr><td align="right">7&nbsp;</td><td><a href="raco-pollen.html" class="tocviewlink" data-pltdoc="x">Using <span class="stt">raco pollen</span></a></td></tr><tr><td align="right">8&nbsp;</td><td><a href="File_formats.html" class="tocviewlink" data-pltdoc="x">File formats</a></td></tr><tr><td align="right">9&nbsp;</td><td><a href="reader.html" class="tocviewlink" data-pltdoc="x">&#9674; command overview</a></td></tr><tr><td align="right">10&nbsp;</td><td><a href="Module_reference.html" class="tocviewlink" data-pltdoc="x">Module reference</a></td></tr><tr><td align="right">11&nbsp;</td><td><a href="Acknowledgments.html" class="tocviewlink" data-pltdoc="x">Acknowledgments</a></td></tr><tr><td align="right">12&nbsp;</td><td><a href="License___source_code.html" class="tocviewselflink" data-pltdoc="x">License &amp; source code</a></td></tr><tr><td align="right"></td><td><a href="doc-index.html" class="tocviewlink" data-pltdoc="x">Index</a></td></tr></table></div></div></div></div><div class="maincolumn"><div class="main"><div class="versionbox"><span class="version">6.1.0.5</span></div><div class="navsettop"><span class="navleft"><div class="nosearchform"></div>&nbsp;&nbsp;</span><span class="navright">&nbsp;&nbsp;<a href="Acknowledgments.html" title="backward to &quot;11 Acknowledgments&quot;" data-pltdoc="x">&larr; prev</a>&nbsp;&nbsp;<a href="index.html" title="up to &quot;Pollen: the book is a program&quot;" data-pltdoc="x">up</a>&nbsp;&nbsp;<a href="doc-index.html" title="forward to &quot;Index&quot;" data-pltdoc="x">next &rarr;</a></span>&nbsp;</div><h3>12<tt>&nbsp;</tt><a name="(part._.License___source_code)"></a>License &amp; source code</h3><p>This module is licensed under the LGPL.</p><p>Source repository at <a href="http://github.com/mbutterick/pollen">http://github.com/mbutterick/pollen</a>. Suggestions &amp; corrections welcome.</p><div class="navsetbottom"><span class="navleft"><div class="nosearchform"></div>&nbsp;&nbsp;</span><span class="navright">&nbsp;&nbsp;<a href="Acknowledgments.html" title="backward to &quot;11 Acknowledgments&quot;" data-pltdoc="x">&larr; prev</a>&nbsp;&nbsp;<a href="index.html" title="up to &quot;Pollen: the book is a program&quot;" data-pltdoc="x">up</a>&nbsp;&nbsp;<a href="doc-index.html" title="forward to &quot;Index&quot;" data-pltdoc="x">next &rarr;</a></span>&nbsp;</div></div></div><div id="contextindicator">&nbsp;</div></body></html>
<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"/><title>13&nbsp;License &amp; source code</title><link rel="stylesheet" type="text/css" href="scribble.css" title="default"/><link rel="stylesheet" type="text/css" href="manual-style.css" title="default"/><link rel="stylesheet" type="text/css" href="manual-racket.css" title="default"/><script type="text/javascript" src="scribble-common.js"></script><script type="text/javascript" src="manual-racket.js"></script><!--[if IE 6]><style type="text/css">.SIEHidden { overflow: hidden; }</style><![endif]--></head><body id="scribble-racket-lang-org"><div class="tocset"><div class="tocview"><div class="tocviewlist tocviewlisttopspace"><div class="tocviewtitle"><table cellspacing="0" cellpadding="0"><tr><td style="width: 1em;"><a href="javascript:void(0);" title="Expand/Collapse" class="tocviewtoggle" onclick="TocviewToggle(this,&quot;tocview_0&quot;);">&#9660;</a></td><td></td><td><a href="index.html" class="tocviewlink" data-pltdoc="x">Pollen:<span class="mywbr"> &nbsp;</span> the book is a program</a></td></tr></table></div><div class="tocviewsublistonly" style="display: block;" id="tocview_0"><table cellspacing="0" cellpadding="0"><tr><td align="right">1&nbsp;</td><td><a href="Installation.html" class="tocviewlink" data-pltdoc="x">Installation</a></td></tr><tr><td align="right">2&nbsp;</td><td><a href="quick-tour.html" class="tocviewlink" data-pltdoc="x">Quick tour</a></td></tr><tr><td align="right">3&nbsp;</td><td><a href="Backstory.html" class="tocviewlink" data-pltdoc="x">Backstory</a></td></tr><tr><td align="right">4&nbsp;</td><td><a href="big-picture.html" class="tocviewlink" data-pltdoc="x">The big picture</a></td></tr><tr><td align="right">5&nbsp;</td><td><a href="first-tutorial.html" class="tocviewlink" data-pltdoc="x">First tutorial</a></td></tr><tr><td align="right">6&nbsp;</td><td><a href="second-tutorial.html" class="tocviewlink" data-pltdoc="x">Second tutorial</a></td></tr><tr><td align="right">7&nbsp;</td><td><a href="third-tutorial.html" class="tocviewlink" data-pltdoc="x">Third tutorial</a></td></tr><tr><td align="right">8&nbsp;</td><td><a href="raco-pollen.html" class="tocviewlink" data-pltdoc="x">Using <span class="stt">raco pollen</span></a></td></tr><tr><td align="right">9&nbsp;</td><td><a href="File_formats.html" class="tocviewlink" data-pltdoc="x">File formats</a></td></tr><tr><td align="right">10&nbsp;</td><td><a href="reader.html" class="tocviewlink" data-pltdoc="x">&#9674; command overview</a></td></tr><tr><td align="right">11&nbsp;</td><td><a href="Module_reference.html" class="tocviewlink" data-pltdoc="x">Module reference</a></td></tr><tr><td align="right">12&nbsp;</td><td><a href="Acknowledgments.html" class="tocviewlink" data-pltdoc="x">Acknowledgments</a></td></tr><tr><td align="right">13&nbsp;</td><td><a href="License___source_code.html" class="tocviewselflink" data-pltdoc="x">License &amp; source code</a></td></tr><tr><td align="right"></td><td><a href="doc-index.html" class="tocviewlink" data-pltdoc="x">Index</a></td></tr></table></div></div></div></div><div class="maincolumn"><div class="main"><div class="versionbox"><span class="version">6.1.0.5</span></div><div class="navsettop"><span class="navleft"><div class="nosearchform"></div>&nbsp;&nbsp;</span><span class="navright">&nbsp;&nbsp;<a href="Acknowledgments.html" title="backward to &quot;12 Acknowledgments&quot;" data-pltdoc="x">&larr; prev</a>&nbsp;&nbsp;<a href="index.html" title="up to &quot;Pollen: the book is a program&quot;" data-pltdoc="x">up</a>&nbsp;&nbsp;<a href="doc-index.html" title="forward to &quot;Index&quot;" data-pltdoc="x">next &rarr;</a></span>&nbsp;</div><h3>13<tt>&nbsp;</tt><a name="(part._.License___source_code)"></a>License &amp; source code</h3><p>This module is licensed under the LGPL.</p><p>Source repository at <a href="http://github.com/mbutterick/pollen">http://github.com/mbutterick/pollen</a>. Suggestions &amp; corrections welcome.</p><div class="navsetbottom"><span class="navleft"><div class="nosearchform"></div>&nbsp;&nbsp;</span><span class="navright">&nbsp;&nbsp;<a href="Acknowledgments.html" title="backward to &quot;12 Acknowledgments&quot;" data-pltdoc="x">&larr; prev</a>&nbsp;&nbsp;<a href="index.html" title="up to &quot;Pollen: the book is a program&quot;" data-pltdoc="x">up</a>&nbsp;&nbsp;<a href="doc-index.html" title="forward to &quot;Index&quot;" data-pltdoc="x">next &rarr;</a></span>&nbsp;</div></div></div><div id="contextindicator">&nbsp;</div></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1,45 @@
/* special styles for custom @fileblock function in mb-tools.rkt */
.noskip .refcolumn {
background: #998;
color: white;
}
.noskip .refcontent p {
font-size: 110%;
line-height: 1.4;
}
.fileblock .SIntrapara {
margin: 0 0 0 0;
}
.fileblock .SCodeFlow {
padding-top: 0.7em;
margin-top: 0;
}
.fileblock {
width: 90%;
}
.fileblock_filetitle{
background: #eee;
text-align:right;
padding: 0.15em;
border: 1px dotted black;
border-bottom: none;
}
.terminal .SIntrapara, .browser .SIntrapara {
margin: 0 0 0 0;
}
.terminal, .browser {
margin-bottom: 1em;
padding: 0.5em;
width: 88%;
background: #fcfcfc;
color: #666;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -297,13 +297,13 @@ For instance, suppose we want to use @tt{map} as a tag even though Racket is usi
@racketoutput{@literal{'(my-map "How I would love this to be a map.")}}
But @code{my-map} is not the tag we want. We need to define @code{my-map} to be a tag function for @tt{map}. We can do this with the Pollen helper @racket[make-tag-function]. That function lives in @racket[pollen/tag], so we @racket[require] that too:
But @code{my-map} is not the tag we want. We need to define @code{my-map} to be a tag function for @tt{map}. We can do this with the Pollen helper @racket[make-default-tag-function]. That function lives in @racket[pollen/tag], so we @racket[require] that too:
@codeblock|{
#lang pollen
◊(require pollen/tag)
◊(define my-map (make-tag-function 'map))
◊(define my-map (make-default-tag-function 'map))
◊my-map{How I would love this to be a map.}
}|

@ -0,0 +1,47 @@
#lang scribble/manual
@(require "mb-tools.rkt")
@fileblock["hello" @bold{world}]
@codeblock|{
#lang pollen
◊define[greeting]{Plain @codeblock.}.
}|
@filebox["foo.html"]{
@codeblock|{
#lang pollen
◊define[greeting]{@codeblock wrapped in @filebox}.
}|}
@racketblock[
(define greeting
"Plain @racketblock")
]
@filebox["foo.html"]{
@racketblock[
(define greeting
"@racketblock wrapped in @filebox")
]}
@racketmod[racket/base
(define greeting
"Plain @racketmod")
]
@racketmod[#:file "foo.html" racket/base
(define greeting
"@racketmod with #:file argument")
]
@filebox["foo.html"]{
Plain #filebox
}

@ -53,9 +53,9 @@ Any value or function that is defined within the source file using @racket[defin
@bold{How is this different from Racket?} In Racket, you must explicitly @racket[provide] any values you want to export. Unlike Racket, every Pollen source file impliedly uses @racket[(provide (all-defined-out))].
@subsection{The @code{@(format "~a" world:project-require)} file}
@subsection{The @code{@(format "~a" world:directory-require)} file}
If a file called @code{@(format "~a" world:project-require)} exists in the same directory with a source file, it's automatically imported when the source file is compiled.
If a file called @code{@(format "~a" world:directory-require)} exists in the same directory with a source file, it's automatically imported when the source file is compiled.
@bold{How is this different from Racket?} In Racket, you must explicitly import files using @racket[require].

@ -0,0 +1,46 @@
#lang racket/base
(require scribble/core scribble/base scribble/manual racket/list scribble/private/manual-sprop scribble/decode scribble/html-properties racket/runtime-path racket/string)
(provide (all-defined-out))
(define-runtime-path mb-css "mb.scss")
(define (racketfont* . args)
(element 'tt args))
(define (fileblock filename . inside)
(compound-paragraph
(style "fileblock" (list* (alt-tag "div") 'multicommand
(box-mode "RfileboxBoxT" "RfileboxBoxC" "RfileboxBoxB")
scheme-properties))
(list
(paragraph (style "fileblock_filetitle" (list* (alt-tag "div") (box-mode* "RfiletitleBox") scheme-properties))
(list (make-element
(style "fileblock_filename" (list (css-style-addition mb-css)))
(if (string? filename)
(filepath filename)
filename))))
(compound-paragraph
(style "fileblock_filecontent" (list* (alt-tag "div") (box-mode* "RfilecontentBox") scheme-properties))
(decode-flow inside)))))
(define (convert-newlines args)
(map (λ(arg) (if (equal? arg "\n") (linebreak) arg)) args))
(define (repl-output . args)
(nested (racketvalfont (racketfont* (convert-newlines args)))))
(define (errorblock . args)
(nested (racketerror (racketfont* (convert-newlines args)))))
(define (browser . args)
(compound-paragraph (style "browser" (list (css-style-addition mb-css) (alt-tag "div"))) (list (paragraph (style #f null) (string-append* args)))))
(define (terminal . args)
(compound-paragraph (style "terminal" (list (css-style-addition mb-css) (alt-tag "div"))) (list (apply verbatim args))))
(define (noskip-note)
(nested #:style (style "noskip" (list (css-style-addition mb-css) (alt-tag "div")))
(margin-note "Dont skip this section! It explains a concept that's essential to understanding how Pollen works.")))

@ -0,0 +1,45 @@
/* special styles for custom @fileblock function in mb-tools.rkt */
.noskip .refcolumn {
background: #998;
color: white;
}
.noskip .refcontent p {
font-size: 110%;
line-height: 1.4;
}
.fileblock .SIntrapara {
margin: 0 0 0 0;
}
.fileblock .SCodeFlow {
padding-top: 0.7em;
margin-top: 0;
}
.fileblock {
width: 90%;
}
.fileblock_filetitle{
background: #eee;
text-align:right;
padding: 0.15em;
border: 1px dotted black;
border-bottom: none;
}
.terminal .SIntrapara, .browser .SIntrapara {
margin: 0 0 0 0;
}
.terminal, .browser {
margin-bottom: 1em;
padding: 0.5em;
width: 88%;
background: #fcfcfc;
color: #666;
}

@ -51,7 +51,7 @@ Or, if you can find a better digital-publishing tool, use that. But I'm never go
@include-section["tutorial-second.scrbl"]
@;include-section["tutorial-third.scrbl"]
@include-section["tutorial-third.scrbl"]
@include-section["raco.scrbl"]

@ -1,5 +1,7 @@
#lang scribble/manual
@(require "mb-tools.rkt")
@title[#:tag "quick-tour"]{Quick tour}
@(define (link-tt url) (link url (tt url)))
@ -11,7 +13,9 @@ Assuming you've installed Racket & Pollen, launch DrRacket.
Open a new document. Change the top line to:
@racketmod[pollen]
@codeblock{
#lang pollen
}
The first line of every Pollen source file will start with @tt{#lang pollen}.
@ -20,12 +24,14 @@ The first line of every Pollen source file will start with @tt{#lang pollen}.
Add a second line to your source file so it reads:
@racketmod[pollen
Hello world]
@codeblock{
#lang pollen
Hello world
}
Click the @onscreen{Run} button. In the interactions window, you'll see the result:
@nested[#:style 'code-inset]{@racketvalfont{Hello world}}
@repl-output{Hello world}
Not bad. I think Pollen just won the @link["http://en.wikipedia.org/wiki/List_of_Hello_world_program_examples"]{Hello World Tournament}.
@ -33,18 +39,23 @@ You can work with Pollen source files in any text editor. The key advantage of D
Try editing your source file:
@racketmod[pollen
@codeblock{
#lang pollen
Goodbye Stranger
Breakfast in America
Take the Long Way Home]
Take the Long Way Home
}
You don't have to use Supertramp song titles. Any text will do. When you click @onscreen{Run} again, you'll see whatever you typed:
@nested[#:style 'code-inset]{@racketvalfont{Goodbye Stranger}@(linebreak)@racketvalfont{Breakfast in America}@(linebreak)@racketvalfont{Take the Long Way Home}}
@repl-output{Goodbye Stranger
Breakfast in America
Take the Long Way Home
}
We won't do it a third time. You get the point — any plain text is valid within a Pollen source file, and gets printed as is. You never have to perform the incantations of typical programming languages:
@verbatim{
@terminal{
print "Hello world"
document.write('Hello world');
printf("Hello world");
@ -59,13 +70,13 @@ Save this file with the name @tt{hello.txt.pp} in any convenient directory. The
Open a terminal window and issue two commands:
@verbatim{
@terminal{
> cd [directory containing your file]
> raco pollen render hello.txt.pp}
After a moment, a new file will appear called @tt{hello.txt}. Let's see what's in it:
@verbatim{
@terminal{
> cat hello.txt
Goodbye Stranger
Breakfast in America
@ -96,13 +107,13 @@ You've just learned two ways to see the output of a Pollen source file — firs
Now here's a third: the Pollen project server. Here's how you start it. Return to your terminal window and issue two commands:
@verbatim{
@terminal{
> cd [directory containing your hello.txt.pp file]
> raco pollen start}
After a moment, you'll see the startup message:
@verbatim{
@terminal{
Welcome to Pollen 0.001 (Racket 6.0.0.5)
Project root is /path/to/your/directory
Project server is http://localhost:8080 (Ctrl-C to exit)
@ -113,7 +124,7 @@ Open a web browser and point it at @link-tt{http://localhost:8080/index.ptree}.
Among them will be @tt{hello.txt}, with a greyed-out @tt{.pp} extension. Click on it, and you'll be taken to @link-tt{http://localhost:8080/hello.txt}, where you'll see:
@verbatim{
@terminal{
Goodbye Stranger
Breakfast in America
Take the Long Way Home
@ -121,14 +132,17 @@ Take the Long Way Home
That's the boring part. Here's the good part. Leave the project server running. Open your source file again in DrRacket and edit it as follows:
@racketmod[#:file "hello.txt.pp" pollen
@fileblock["hello.txt.pp"
@codeblock{
#lang pollen
Mean Street
Panama
Hear About It Later]
Hear About It Later
}]
Go back to your web browser and reload @link-tt{http://localhost:8080/hello.txt}. Now you'll see this:
@verbatim{
@terminal{
Mean Street
Panama
Hear About It Later}
@ -148,10 +162,13 @@ A @italic{preprocessor} is a tool for making systematic, automated changes to a
For instance, HTML. In DrRacket, create a new file called @tt{margin.html.pp} in your project directory:
@racketmod[#:file "margin.html.pp" pollen
@fileblock["margin.html.pp"
@codeblock{
#lang pollen
<body style="margin: 5em; border:1px solid black">
5em is the inset.
</body>]
</body>
}]
The ``@tt{.pp}'' file extension — which you saw before, with @tt{hello.txt.pp} — stands for ``Pollen preprocessor.'' You can use the Pollen preprocessor with any text-based file by inserting @tt{#lang pollen} as the first line, and adding the @tt{.pp} file extension.
@ -159,12 +176,14 @@ But for now, go to your @link["http://localhost:8080/index.ptree"]{project dashb
Let's suppose you want to change the inset to 30%. Without a preprocessor, you'd have to search & replace each value. But with a preprocessor, you can move the inset value into a variable, and update it from that one location. So first, introduce a variable called @tt{my-inset} by using the @racket[define] command:
@racketmod[#:file "margin.html.pp" pollen
@fileblock["margin.html.pp"
@codeblock{
#lang pollen
◊define[my-inset]{30%}
<body style="margin: 10em; border:1px solid black">
10em is the inset.
</body>
]
}]
The ◊ character is called a @italic{lozenge}. In Pollen, the lozenge is a special character that marks anything Pollen should interpret as a command (rather than plain text).
@ -177,12 +196,14 @@ The whole command @tt{◊define[my-inset]{30%}} means ``create a variable called
Then put the variable into the HTML like so, this time using the ◊ character with the variable name in the two places the value appears:
@racketmod[#:file "margin.html.pp" pollen
@fileblock["margin.html.pp"
@codeblock{
#lang pollen
◊define[my-inset]{30%}
<body style="margin: ◊my-inset; border:1px solid black">
◊my-inset is the inset.
</body>
]
}]
Now reload @link["http://localhost:8080/margin.html"]{@tt{margin.html}}. You'll see that the size of the margin has changed (because of the change to the @tt{style} attribute) and so has the text of the HTML. If you like, try editing @tt{my-inset} with different values and reloading the page. You can also try using @racket[define] to create another variable (for instance, to change the color of the box border).
@ -196,7 +217,9 @@ For instance, Markdown mode. Markdown is a simplified @link["https://daringfireb
Try it. In DrRacket, create a file with the following lines and save it as @tt{downtown.html.pmd}:
@racketmod[#:file "downtown.html.pmd" pollen
@fileblock["downtown.html.pmd"
@codeblock{
#lang pollen
Pollen + Markdown
-----------------
@ -204,7 +227,7 @@ Pollen + Markdown
+ You **wanted** it — you #,(racketfont "_got_") it.
+ [search for Racket](https://google.com/search?q=racket)
]
}]
As before, go to the @link["http://localhost:8080/index.ptree"]{dashboard} for the project server. This time, click the link for @link["http://localhost:8080/downtown.html"]{@tt{downtown.html}}. You'll see something like this:
@ -222,7 +245,9 @@ As usual, you're welcome to edit @tt{downtown.html.pmd} and then refresh the web
In Markdown mode, you can still embed Pollen commands within the source as you did in preprocessor mode. Just keep in mind that your commands need to produce valid Markdown (as opposed to raw HTML). For instance, use @tt{define} to create a variable called @tt{metal}, and insert it into the Markdown:
@racketmod[#:file "downtown.html.pmd" pollen
@fileblock["downtown.html.pmd"
@codeblock{
#lang pollen
◊define[metal]{Plutonium}
Pollen + ◊metal
@ -231,7 +256,7 @@ Pollen + ◊metal
+ You **wanted** ◊metal — you #,(racketfont "_got_") it.
+ [search for ◊metal](https://google.com/search?q=◊metal)
]
}]
Refresh @link["http://localhost:8080/downtown.html"]{@tt{downtown.html}} in the browser:
@ -260,17 +285,16 @@ Let's convert our Markdown example into Pollen markup. Marking up content is sim
@racketmod[#:file "uptown.html.pm" pollen
@fileblock["uptown.html.pm"
@codeblock{
#lang pollen
◊headline{Pollen markup}
◊items{
◊item{You ◊strong{wanted} it — you ◊em{got} it.}
◊item{◊link["https://google.com/search?q=racket"]{search for Racket}}
}]
◊item{You ◊strong{wanted} it — you ◊em{got} it.}
◊item{◊link["https://google.com/search?q=racket"]{search for Racket}}
}}]
Go to the @link["http://localhost:8080/index.ptree"]{project dashboard} and click on @link["http://localhost:8080/uptown.html"]{@tt{uptown.html}}. You'll see something like this:
@ -281,16 +305,19 @@ That's not right. What happened?
We marked up the source using a combination of standard HTML tags (@tt{strong}, @tt{em}) and nonstandard ones (@tt{headline}, @tt{items}, @tt{item}, @tt{link}). This is valid Pollen markup. (In fact, if you look at @link["http://localhost:8080/out/markup.html"]{the generated source}, you'll see that they didn't disappear.) But since we're targeting HTML, we need to convert our custom tags into valid HTML tags.
For that, we'll make a special file called @tt{project-require.rkt}. This is a file in the standard Racket language that provides helper functions to decode the source. The definitions won't make sense yet. But this is the quick tour, so all you need to do is copy, paste, and save:
For that, we'll make a special file called @tt{directory-require.rkt}. This is a file in the standard Racket language that provides helper functions to decode the source. The definitions won't make sense yet. But this is the quick tour, so all you need to do is copy, paste, and save:
@fileblock["directory-require.rkt"
@codeblock{
#lang racket/base
@racketmod[#:file "project-require.rkt" racket/base
(require pollen/tag)
(provide (all-defined-out))
(define headline (make-tag-function 'h2))
(define items (make-tag-function 'ul))
(define item (make-tag-function 'li 'p))
(define headline (make-default-tag-function 'h2))
(define items (make-default-tag-function 'ul))
(define item (make-default-tag-function 'li 'p))
(define (link url text) `(a [[href ,url]] ,text))
]
}]
Return to the @link["http://localhost:8080/index.ptree"]{project dashboard} and click on @link["http://localhost:8080/uptown.html"]{@tt{uptown.html}}. Now you'll get the right result:
@ -316,7 +343,9 @@ When it needs a template, Pollen first looks for a file in the project directory
So let's create @tt{template.html}. Make a new file that with the following lines and save it to the same directory as @tt{uptown.html.pm}:
@filebox["template.html"]{@verbatim{<html><head><meta charset="UTF-8"/></head>
@fileblock["template.html"
@codeblock{
<html><head><meta charset="UTF-8"/></head>
<body style="background: #f6f6f6">
<div style="background: white; margin: 3em;
border:10px double gray; padding: 3em; font-size: 130%;">
@ -324,7 +353,7 @@ This file is ◊here
<hr />
◊->html{◊doc}
</div></body></html>
}}
}]
This is a simple HTML file that should look familiar, except for the two template variables. The first, @tt{here}, contains the name of the current source file. As before, the lozenge character marks it as a Pollen command rather than text, so you write it as @tt{◊here}. The other command, @tt{◊->html{◊doc}}, takes the content from the source file, which is contained in a variable called @tt{doc}, and converts it to HTML with a Pollen function called @tt{->html}.
@ -334,7 +363,7 @@ Go back to your web browser and reload @link["http://localhost:8080/uptown.html"
Pollen can also be used as a dynamic preview server for Scribble files. From your terminal, do the following:
@verbatim{
@terminal{
> cd [directory containing your Scribble files]
> raco pollen start}

@ -13,14 +13,14 @@ Convenience functions for working with tags.
@defproc[
(make-tag-function
(make-default-tag-function
[id txexpr-tag?])
(-> txexpr?)]
Make a tag function for @racket[_id]. As arguments, a tag function takes an optional set of X-expression attributes (@racket[txexpr-attrs?]) followed by X-expression elements (@racket[txexpr-elements?]). From these, the tag function creates a tagged X-expression using @racket[_id] as the tag.
Make a default tag function for @racket[_id]. As arguments, a tag function takes an optional set of X-expression attributes (@racket[txexpr-attrs?]) followed by X-expression elements (@racket[txexpr-elements?]). From these, the tag function creates a tagged X-expression using @racket[_id] as the tag.
@examples[
(require pollen/tag)
(define beaucoup (make-tag-function 'em))
(define beaucoup (make-default-tag-function 'em))
(beaucoup "Bonjour")
(beaucoup '((id "greeting")) "Bonjour")
]
@ -29,7 +29,7 @@ Entering attributes this way can be cumbersome. So for convenience, a tag functi
@examples[
(require pollen/tag)
(define beaucoup (make-tag-function 'em))
(define beaucoup (make-default-tag-function 'em))
(beaucoup 'id: "greeting" 'class: "large" "Bonjour")
(code:comment @#,t{Don't forget the colons})
(beaucoup 'id "greeting" 'class "large" "Bonjour")
@ -38,3 +38,19 @@ Entering attributes this way can be cumbersome. So for convenience, a tag functi
]
Pollen also uses this function to provide the default behavior for undefined tags. See @racket[#%top].
@defproc[
(split-attributes
[parts list?])
(values txexpr-attrs? txexpr-elements?)]
Helper function for custom tag functions. Take a rest argument that possibly includes tag attributes plus elements, and split it into attributes and elements. If there are no attributes, that return value will be the empty list. Properly parses the abbreviated Pollen syntax for attributes (described in @racket[make-default-tag-function]).
@examples[
(require pollen/tag)
(define (tag . parts)
(define-values (attrs elements) (split-attributes parts))
(values attrs elements))
(tag "Hello world")
(tag '((key "value")) "Hello world")
(tag 'key: "value" "Hello world")
]

@ -25,7 +25,7 @@ In standard Racket, @racket[#%top] is the function of last resort, called when @
In the Pollen markup environment, however, this behavior is annoying. Because when you're writing X-expressions, you don't necessarily want to define all your tags ahead of time.
So Pollen redefines @racket[#%top]. For convenience, Pollen's version of @racket[#%top] assumes that an undefined tag should just refer to an X-expression beginning with that tag (and uses @racket[make-tag-function] to provide this behavior):
So Pollen redefines @racket[#%top]. For convenience, Pollen's version of @racket[#%top] assumes that an undefined tag should just refer to an X-expression beginning with that tag (and uses @racket[make-default-tag-function] to provide this behavior):
@examples[
(code:comment @#,t{Again, let's call em without defining it, but using pollen/top})

@ -1,6 +1,6 @@
#lang scribble/manual
@(require (for-label pollen/world))
@(require (for-label pollen/world) racket/runtime-path "mb-tools.rkt")
@title[#:tag "first-tutorial"]{First tutorial}
@ -56,11 +56,13 @@ DrRacket is the IDE for the Racket programming language, and other languages mad
Launch DrRacket. Start a new file. The code in the file will look like this:
@racketmod[racket]
@codeblock{
#lang racket
}
Within the main window, you should also see an @italic{interactions window}, which shows the output of the current file, and starts out looking something like this (details, like the version number, will vary):
@verbatim{
@terminal{
Welcome to DrRacket, version 6.0.1.6--2013-11-26(-/f) [3m].
Language: racket; memory limit: 1000 MB.
> }
@ -72,15 +74,17 @@ If you don't see the interactions window, select @menuitem["View"
The first line of every Racket source file, and every Pollen source file, is called the @italic{@racketfont{#lang} line}. The @racketfont{#lang} line identifies the language used to interpret the rest of the file.
@margin-note{For more about the @racketfont{#lang} line, see @secref[#:doc '(lib "scribblings/guide/guide.scrbl") "hash-lang"].}
@margin-note{For more about the @racketfont{#lang} line, see @secref["hash-languages" #:doc '(lib "scribblings/guide/guide.scrbl")]. BTW, it's pronounced @italic{hash lang}.}
When you start a new Pollen source file in DrRacket, you'll need to change the @racketfont{#lang} line to the Pollen language. The simplest way is to change the first line to this:
@racketmod[pollen]
@codeblock{
#lang pollen
}
Now run your file by clicking the @onscreen["Run"] button in the upper-right corner, or select @menuitem["Racket" "Run"] from the menu. You'll get something like:
@verbatim{
@terminal{
Welcome to DrRacket, version 6.0.1.6--2013-11-26(-/f) [3m].
Language: pollen; memory limit: 1000 MB.
>
@ -93,8 +97,8 @@ Notice that the language is now reported as @racketfont{pollen}. If you like, ch
Then click @onscreen["Run"] again. DrRacket will print an error:
@verbatim{@racketerror{Module Language: invalid module text
@(linebreak)standard-module-name-resolver: collection not found ...}}
@errorblock{Module Language: invalid module text
standard-module-name-resolver: collection not found ...}
Why? Because there's no language called @racketfont{pollenxyz}. Switch it back to @racketfont{pollen} and let's move on.
@ -102,7 +106,7 @@ Why? Because there's no language called @racketfont{pollenxyz}. Switch it back t
Here's a short, bad poem I wrote about CSS.
@verbatim{
@terminal{
The margin is 42em.
The border is red.
The padding is 15em.
@ -111,26 +115,28 @@ The border is too.
Paste the text of this poem into your DrRacket editing window, below the @racketfont{#lang} line, so it looks like this:
@nested[#:style 'code-inset]{@verbatim{
@codeblock{
#lang pollen
The margin is 42em.
The border is red.
The padding is 15em.
The border is too.}}
The border is too.}
@onscreen["Run"] the file again. In the interactions window, you'll see:
@racketvalfont{
@repl-output{
The margin is 8em.
@(linebreak)The border is blue.
@(linebreak)The padding is 2em.
@(linebreak)The border is too.}
The border is blue.
The padding is 2em.
The border is too.}
This shows you something important: by default, any plain text in a Pollen source file is simply printed as written when you @onscreen["Run"] the file (minus the @racketfont{#lang} line, which is just for Racket's benefit). If you like, edit the text of the poem and click @onscreen["Run"] again. You'll see the updated text printed in the interactions window.
@subsection{Saving & naming your source file}
@(noskip-note)
File naming in Pollen is consequential.
Ultimately, every Pollen source file in your project will be @italic{rendered} into an output file. Each Pollen source file corresponds to one output file. @bold{The name of this output file will be the name of the source file minus the Pollen source extension.} So a source file called @racketfont{file.txt.pp} will become @racketfont{file.txt}.
@ -147,20 +153,22 @@ the output name @racketfont{poem.html} + the source extension @racketfont{.pp} =
In a convenient location (e.g., your home directory or the desktop) create a new directory for your project called @racketfont{tutorial}. In this new directory, save your DrRacket file as @racketfont{poem.html.pp}.
@filebox["/path/to/tutorial/poem.html.pp"]{@verbatim{
@fileblock["/path/to/tutorial/poem.html.pp" @codeblock{
#lang pollen
The margin is 42em.
The border is red.
The padding is 15em.
The border is too.}}
The border is too.
}]
@section{Using the project server}
The project server is a web server built into Pollen. Just as DrRacket lets you run individual files and see if they work as you expect, the project server lets you preview and test your project as a real website. While working on your Pollen project, you may find it convenient to have DrRacket open on half your screen, and on the other half, a web browser pointing at the project server.
@image["scribblings/project-server.png" #:scale 0.7]
@(define-runtime-path project-server "project-server.png")
@image[project-server #:scale 0.7]
``Why can't I just open the HTML files directly in my browser?'' If you want to keep making web pages the way we did in 1996, go ahead. But that approach has several shortcomings. First, when you open files directly in your browser, you're cruising the local filesystem, and absolute URLs (the kind that start with a @litchar{/}) won't work. Second, if you want to test your website on devices other than your own machine — well, you can't. Third, you have to render your HTML files in advance, whereas the project server is clever about doing this dynamically.
@ -176,13 +184,13 @@ Before we start the project server, a word about the @racketfont{raco pollen} co
When you installed Racket, Racket installed a utility program called @racketfont{raco}. This name is short for @bold{Ra}cket @bold{co}mmand, and @racketfont{raco} acts as a hub for — you guessed it — Racket commands. You used it when you first installed Pollen:
@verbatim{
@terminal{
> raco pkg install pollen
}
The first argument after @racketfont{raco} is the subcommand. For instance, @racketfont{raco pkg ...} lets you install, update, and remove packages like so:
@verbatim{
@terminal{
> raco pkg update pollen
> raco pkg remove pollen
}
@ -191,7 +199,7 @@ Likewise, @racketfont{raco pollen} lets you issue commands relevant to Pollen, l
Now we'll start the project server. Go to your command line and enter the following:
@verbatim{
@terminal{
> cd /path/to/tutorial
> raco pollen start}
@ -199,7 +207,7 @@ Now we'll start the project server. Go to your command line and enter the follow
After a moment, you'll see a startup message like this:
@verbatim{
@terminal{
Welcome to Pollen 0.001 (Racket 6.x.x.x)
Project root is /path/to/tutorial
Project server is http://localhost:8080 (Ctrl-C to exit)
@ -210,7 +218,7 @@ Ready to rock}
If you use the bare command @racketfont{raco pollen start}, the project server will start in the current directory. But if you want to start the project server elsewhere, you can add that directory as an argument like this:
@verbatim{
@terminal{
> raco pollen start /some/other/path
}
@ -220,20 +228,21 @@ If you want to access the project server from a different machine, you can't use
Though port @racketfont{8080} is the default, you can start the project server on any port you like by adding it as an argument to @racketfont{raco pollen start}:
@verbatim{
@terminal{
> raco pollen start /path/to/tutorial
> raco pollen start /path/to/tutorial 8088
}
@margin-note{You can also change the default port by altering @racket[world:default-port], or parameterizing it with @racket[world:current-server-port].}
Note that when you pass a port argument, you also have to pass a path argument. If you want the project server to start in the current directory, you can use the usual @litchar{.} shorthand:
Note that when you pass a port argument, you also have to pass a path argument. (Without it, you'll get an error, as illustrated below.) If you want the project server to start in the current directory, you can use the usual @litchar{.} shorthand:
@verbatim{
@terminal{
> cd /path/to/tutorial
> raco pollen start 8088
@racketerror{/path/to/tutorial/8088 is not a directory}
> raco pollen start . 8088
Welcome to Pollen 0.001 (Racket 6.x.x.x) ...
}
@margin-note{You can run multiple project servers simultaneously. Just start them on different ports so they don't conflict with each other.}
@ -253,7 +262,7 @@ Thus, @racketfont{index.ptree}. The @racketfont{.ptree} extension is short for @
Let's look at the root-level dashboard for our project. First, make sure your project server is running:
@verbatim{
@terminal{
> cd /path/to/tutorial
> raco pollen start
}
@ -262,7 +271,8 @@ Then, in your web browser, visit @link["http://localhost:8080/index.ptree"]{@rac
You should see something like this:
@image["scribblings/dashboard.png" #:scale 1]
@(define-runtime-path dashboard "dashboard.png")
@image[dashboard #:scale 1]
The top line tells us that we're in the root directory of the project. We didn't make an explicit @racketfont{index.ptree} file, so the project server just shows us a directory listing.
@ -273,7 +283,7 @@ We see the only file, @racketfont{poem.html.pp}. Note that the @racketfont{.pp}
Every source-file entry in the dashboard has three links. The first link is attached to the filename itself, and takes you to a preview of the output file. If the output file doesn't yet exist — as is the case here — it will be dynamically rendered. (This is true whether you click its name in the dashboard, or link to it from another page.) So click the filename. You'll see in your web browser:
@nested[#:style 'code-inset]{
@browser{
The margin is 42em. The border is red. The padding is 15em. The border is too.}
Granted, this is a boring web page. The main point here is that you're seeing the @italic{output} from your source file, which didn't exist before. Notice that the address bar says @racketfont{http://localhost:8080/poem.html}, not @racketfont{poem.html.pp}. And if you look in your @racketfont{tutorial} directory, you'll see a new file called @racketfont{poem.html}.
@ -284,17 +294,18 @@ If you go back to the dashboard and click on the filename link again, you'll see
But if you like, open your @racketfont{poem.html.pp} source file in DrRacket, edit the first two lines, and save the file:
@nested[#:style 'code-inset]{@verbatim{
@codeblock{
#lang pollen
The cave is pitch black.
Look out for the grue.
The padding is 15em.
The border is too.}}
The border is too.
}
Go back to the dashboard and click on the filename. This time, you'll see:
@nested[#:style 'code-inset]{
@browser{
The cave is pitch black. Look out for the grue. The padding is 15em. The border is too.}
Here, Pollen notices that the source file has changed, so it refreshes the output file. This makes it convenient to work between DrRacket and your web browser, editing source and then reloading to see the changes.
@ -303,21 +314,22 @@ The other two links in the dashboard are labeled @racketfont{in} and @racketfont
The link labeled @racketfont{in} will display the contents of the source file:
@nested[#:style 'code-inset]{@verbatim{
@codeblock{
#lang pollen
The cave is pitch black.
Look out for the grue.
The padding is 15em.
The border is too.}}
The border is too.
}
The link labeled @racketfont{out} will display the contents of the output file (just like the ``view source'' option in your web browser):
@nested[#:style 'code-inset]{@verbatim{
@terminal{
The cave is pitch black.
Look out for the grue.
The padding is 15em.
The border is too.}}
The border is too.}
For now, the files are identical except for the @racketfont{#lang} line. But let's change that.
@ -343,27 +355,28 @@ The file extension of a Pollen source file tells Pollen what kind of processing
``The preprocessor be used with @bold{any} kind of text-based file?'' Right. ``But how?'' The preprocessor reads the source file, handles any Pollen commands it finds, and lets the rest of the content pass through untouched. To the preprocessor, it's all just text data. It doesn't care whether that text represents HTML, CSS, JavaScript, or even @link["https://en.wikipedia.org/wiki/TI-BASIC"]{TI-BASIC}.
Because the preprocessor only deals in text, the Pollen commands you use in the preprocessor also have to produce text. Moreover, Pollen doesn't enforce the semantics of the underlying file — that's your responsibility. For instance, Pollen won't stop you from doing nonsensical things like this:
One caveat: because the preprocessor only deals with text, the Pollen commands you use in the preprocessor also have to produce text. Moreover, Pollen doesn't enforce the syntax rules of the underlying file — that's your responsibility. For instance, Pollen won't stop you from doing nonsensical things like this:
@filebox["bad-poem.html.pp"]{@verbatim{
@fileblock["bad-poem.html.pp" @codeblock{
#lang pollen
The cave is pitch black.
Look out for the grue.
◊(insert-mp3-recording-of-scream)
}}
}]
Here, the result is not going to be valid HTML, because you can't simply drop binary data in the middle of an HTML file. To paraphrase Mr. Babbage — garbage in, garbage out.
Pollen will fulfill your request, but the result won't be valid HTML, because you can't simply drop binary data in the middle of an HTML file. To paraphrase Mr. Babbage — garbage in, garbage out.
I've encouraged you to mess with the source file, but let's return it to its original state:
@filebox["/path/to/tutorial/poem.html.pp"]{@verbatim{
@fileblock["/path/to/tutorial/poem.html.pp" @codeblock{
#lang pollen
The margin is 42em.
The border is red.
The padding is 15em.
The border is too.}}
The border is too.
}]
This file has @racketfont{#lang pollen} as the first line, and @racketfont{.pp} as the file extension, so it meets the minimum requirements for the preprocessor.
@ -371,7 +384,7 @@ This file has @racketfont{#lang pollen} as the first line, and @racketfont{.pp}
Let's update our source so it produces valid HTML. Edit the source as follows:
@filebox["/path/to/tutorial/poem.html.pp"]{@verbatim{
@fileblock["/path/to/tutorial/poem.html.pp" @codeblock{
#lang pollen
<!DOCTYPE html>
<html>
@ -383,21 +396,21 @@ The padding is 15em.
The border is too.
</pre>
</body>
</html>}}
</html>}]
Return to the project server and view @link["http://localhost:8080/poem.html" "http://localhost:8080/poem.html"]. Earlier, the output looked like this:
@nested[#:style 'code-inset]{
@browser{
The margin is 42em. The border is red. The padding is 15em. The border is too.}
But now, because of the @racketfont{<pre>} tag, the poem will appear in a monospaced font, and the line breaks will be preserved:
@nested[#:style 'code-inset]{
@tt{The margin is 42em.
@(linebreak)The border is red.
@(linebreak)The padding is 15em.
@(linebreak)The border is too.}}
@terminal{
The margin is 42em.
The border is red.
The padding is 15em.
The border is too.}
As before, because the source has changed, Pollen refreshes the output file. From the dashboard, you can use the @racketfont{in} and @racketfont{out} links to inspect the source and output.
@ -409,21 +422,23 @@ I mentioned that the preprocessor reads the file and handles any Pollen commands
Pollen commands can be embedded in your source file using one of two modes: @italic{Racket mode} or @italic{text mode}. We'll try text mode in a later tutorial. For now, we'll use Racket mode.
To make a Racket-mode Pollen command, just take any Racket expression and put the lozenge character (@litchar["◊"]) in front of it. For instance, these are valid Racket expressions:
To make a Racket-mode Pollen command, just take any Racket expression and put the lozenge character @litchar["◊"] in front of it. For instance, these are valid Racket expressions:
@nested[#:style 'code-inset]{@verbatim{
(define inner 2)
(define edge (* inner 4))
(define color "blue")
}}
@codeblock{
#lang racket
(define inner 2)
(define edge (* inner 4))
(define color "blue")
}
And these are the equivalent commands in Pollen:
@nested[#:style 'code-inset]{@verbatim{
◊(define inner 2)
◊(define edge (* inner 4))
◊(define color "blue")
}}
@codeblock{
#lang pollen
◊(define inner 2)
◊(define edge (* inner 4))
◊(define color "blue")
}
How to type a lozenge:
@(linebreak)@bold{Mac}: option + shift + V
@ -432,7 +447,7 @@ How to type a lozenge:
@subsection{Racket basics (if you're not familiar)}
``But how am I supposed to know Racket?'' You don't. So we'll start now. Here are the five basic rules of Racket:
``But I've never used Racket.'' Today, you start. Here are the five basic rules of Racket:
@itemlist[#:style 'ordered
@ -452,14 +467,15 @@ How to type a lozenge:
That should tell you enough to infer what's going on in the Pollen commands above:
@nested[#:style 'code-inset]{@verbatim{
◊(define inner 2)
◊; create a variable 'inner' that holds the value 2
◊(define edge (* inner 4))
◊; create a variable 'edge' that's four times the value of 'inner'
◊(define color "blue")
◊; create a variable 'color' that holds the value "blue"
}}
@codeblock{
#lang pollen
◊(define inner 2)
◊; create a variable 'inner' that holds the value 2
◊(define edge (* inner 4))
◊; create a variable 'edge' that's four times the value of 'inner'
◊(define color "blue")
◊; create a variable 'color' that holds the value "blue"
}
To learn more about Racket syntax, consider a detour through the excellent @other-doc['(lib "scribblings/quick/quick.scrbl")].
@ -468,8 +484,9 @@ To learn more about Racket syntax, consider a detour through the excellent @othe
Let's use commands to define variables that will hold some values for our page. First, add a @racketfont{<head>} tag to your source file, and three commmands to define three variables:
@filebox["/path/to/tutorial/poem.html.pp"]{@verbatim{
@fileblock["/path/to/tutorial/poem.html.pp" @codeblock{
#lang pollen
<!DOCTYPE html>
<html>
<head>
@ -485,11 +502,11 @@ The padding is 15em.
The border is too.
</pre>
</body>
</html>}}
</html>}]
Then look at @link["http://localhost:8080/poem.html" "http://localhost:8080/poem.html"] again. Does it look the same? Not a trick question — it should. If you click the @onscreen{Out} link on the dashboard, you'll see this:
@nested[#:style 'code-inset]{@verbatim{
@terminal{
<!DOCTYPE html>
<html>
<head>
@ -505,16 +522,17 @@ The padding is 15em.
The border is too.
</pre>
</body>
</html>}}
</html>}
What's happening here? Our @racketfont{◊(define ...)} commands just define variables, so they don't evaluate to any value. Instead, we get blank lines. So far, so good.
What's with the blank lines? Don't panic — our @racketfont{◊(define ...)} commands define variables, so they don't evaluate to any value. Instead, we get blank lines. So far, so good.
@subsection{Inserting values from variables}
To insert the value of a variable in our file, we use the command @litchar{◊|}@italic{variable-name}@litchar{|}. Let's do that now:
@filebox["/path/to/tutorial/poem.html.pp"]{@verbatim{
@fileblock["/path/to/tutorial/poem.html.pp" @codeblock{
#lang pollen
<!DOCTYPE html>
<html>
<head>
@ -530,15 +548,15 @@ The padding is ◊|inner|em.
The border is too.
</pre>
</body>
</html>}}
</html>}]
Here, we're replacing three values in the poem with the variables containing those values — @racketfont{◊|edge|}, @racketfont{◊|color|}, and @racketfont{◊|inner|}. @link["http://localhost:8080/poem.html"]{Reload the file} in the project server, and you'll see:
@nested[#:style 'code-inset]{@verbatim{
@terminal{
The margin is 8em.
The border is blue.
The padding is 2em.
The border is too.}}
The border is too.}
Hey, look at that — the text of the poem changed. Now it even rhymes.
@ -551,8 +569,10 @@ Our poem makes claims about the @racketfont{margin}, @racketfont{border}, and @r
Update the @racketfont{<head>} section of the page with a new @racketfont{<style>} tag that defines a style for @racketfont{pre} like so, using our variables for the relevant values:
@filebox["/path/to/tutorial/poem.html.pp"]{@verbatim{
@fileblock["/path/to/tutorial/poem.html.pp"
@codeblock{
#lang pollen
<!DOCTYPE html>
<html>
<head>
@ -575,7 +595,8 @@ The padding is ◊|inner|em.
The border is too.
</pre>
</body>
</html>}}
</html>
}]
Notice that we're using the same @litchar{◊|}@italic{variable-name}@litchar{|} pattern as before to insert the variable values.
@ -583,7 +604,8 @@ What do we expect to see? We expect that the @racketfont{padding} and @racketfon
And indeed, when you @link["http://localhost:8080/poem.html"]{reload the file} in the project server, you'll see exactly that:
@image["scribblings/result.png" #:scale 0.7]
@(define-runtime-path result "result.png")
@image[result #:scale 0.7]
As before, if you edit the values of the variables in the source file and reload in the project server, you'll see both the text and the layout change.

@ -0,0 +1,100 @@
#lang scribble/manual
@(require scribble/eval (for-label pollen/world pollen/tag racket/base pollen/template txexpr))
@(require "mb-tools.rkt")
@(define my-eval (make-base-eval))
@(my-eval `(require pollen pollen/decode pollen/template pollen/tag xml racket/list txexpr))
@title[#:tag "third-tutorial"]{Fourth tutorial}
@itemlist[
@item{You can use any function in any kind of source file}
@item{Decoding}
@item{Metas}
@item{Hierarchical pagetrees}
@item{Forcing unbound-identifier errors}
@item{Embedding HTML or XML}
]
@section{Sharing data between preprocessor files}
The preprocessor is useful for inserting variables that hold values. But variables are only useful when they can be shared among multiple files. Let's look at one way to do that.
Any value in a Pollen file that's set up using @racket[define] can be pulled into another Pollen file using the @racket[require] function. For instance, let's set up another preprocessor file in the same directory as @racketvalfont["brennan.md.pp"], called @racketvalfont["dale.md.pp"]:
@filebox["dale.md.pp"]{@verbatim{
#lang pollen
My name is _Dale_, and I enjoy:
+ super-duper boring sauce
+ at least 3 fish nuggets}}
In the project server, this will produce the expected output:
@nested[#:style 'code-inset]{@verbatim{
My name is _Dale_, and I enjoy:
+ super-duper boring sauce
+ at least 3 fish nuggets}}
Now, let's update the content using values defined in @racketvalfont{brennan.md.pp}. We do this by adding the @racket[require] command to the top of our file:
@filebox["dale.md.pp"]{@verbatim{
#lang pollen
◊(require "brennan.md.pp")
My name is _Dale_, and I enjoy:
+ super-duper boring sauce
+ at least 3 fish nuggets}}
The three values that we defined in @racketvalfont{brennan.md.pp} — @racketvalfont{sauce-type}, @racketvalfont{nugget-type}, and @racketvalfont{nugget-quantity} — will now be available in @racketvalfont{dale.md.pp} under the same names, so we can insert them into the Markdown in the same way:
@filebox["dale.md.pp"]{@verbatim{
#lang pollen
◊(require "brennan.md.pp")
My name is _Dale_, and I enjoy:
+ super-duper ◊sauce-type sauce
+ at least ◊nugget-quantity ◊nugget-type nuggets}}
Reload the file in the project server, and you'll see the imported values:
@nested[#:style 'code-inset]{@verbatim{
My name is _Dale_, and I enjoy:
+ super-duper fancy sauce
+ at least 12 chicken nuggets}}
@margin-note{Those familiar with Racket know that Racket makes you explicitly @racket[provide] any variables you want to export. To make life simpler, Pollen inverts this behavior and automatically exports all defined symbols using @racket[(provide (all-defined-out))]. For more about the differences in behavior between Racket and Pollen, see @secref["File_formats" #:doc '(lib "pollen/scribblings/pollen.scrbl")].}

@ -2,6 +2,8 @@
@(require (for-label racket pollen/world pollen/template pollen/pagetree sugar))
@(require "mb-tools.rkt")
@title[#:tag "second-tutorial"]{Second tutorial}
In this tutorial, you'll use Pollen to publish a multiple-page article written in Markdown. You'll learn about:
@ -58,31 +60,37 @@ Because Markdown is a text-based format, you can use the Pollen preprocessor to
Suppose we have a Markdown file called @tt{brennan.md} that we want to use with the preprocessor. Create this file in DrRacket, save it, and start the project server in that directory.
@filebox["brennan.md"]{@verbatim{
@fileblock["brennan.md"
@codeblock[#:keep-lang-line? #f]{
#lang pollen
My name is _Brennan_, and I enjoy:
+ boring sauce
+ 24 fish nuggets}}
+ 24 fish nuggets
}]
You'll be able to see this file in the project server, but for now, it's just a static file. Pollen isn't doing anything to it.
Let's change that. Consistent with the usual preprocessor practice, we add @racketfont{#lang pollen} as the first line, and append the @racketfont{.pp} file extension, so our new preprocessor-ready file looks like this:
@filebox["brennan.md.pp"]{@verbatim{
@fileblock["brennan.md.pp"
@codeblock{
#lang pollen
My name is _Brennan_, and I enjoy:
+ boring sauce
+ 24 fish nuggets}}
+ 24 fish nuggets
}]
Go back to the project server and you'll see the new filename. When you click on it, Pollen will render a new @racketfont{markdown.md} file, but it will look the same as the one you had before.
Now we'll change some of the values using Pollen commands:
@filebox["brennan.md.pp"]{@verbatim{
@fileblock["brennan.md.pp"
@codeblock{
#lang pollen
◊(define sauce-type "fancy")
@ -93,16 +101,17 @@ My name is _Brennan_, and I enjoy:
+ ◊sauce-type sauce
+ ◊nugget-quantity ◊nugget-type nuggets}}
+ ◊nugget-quantity ◊nugget-type nuggets
}]
When you reload this file in the project server, @racketfont{brennan.md} will be regenerated, and will now look like this:
@nested[#:style 'code-inset]{@verbatim{
@terminal{
My name is _Brennan_, and I enjoy:
+ fancy sauce
+ 12 chicken nuggets}}
+ 12 chicken nuggets}
@ -123,7 +132,7 @@ Pollen offers two variants of authoring mode: one that uses Markdown syntax (whi
@subsection{X-expressions}
@margin-note{Don't skip this part! It's not the same old shit. And it describes a concept that's key to how Pollen works.}
@(noskip-note)
I avoid nerdy jargon whenever possible. But in this case, the thing is called an @italic{X-expression} throughout the Racket documentation, for good reasons. So I use the term too. Better to acclimate you now.
@ -131,31 +140,31 @@ An X-expression is a way of representing markup-based data in code. X-expression
Let's start with the part you're familiar with. By ``markup-based data,'' I mean things like HTML and XML and SVG. The idea is that you have text-based data surrounded by @italic{tags}. Each tag can also have its own @italic{attributes} that are made of keys and values. Tags can contain other tags, thus creating a tree-like structure. Right? You know what I mean:
@nested[#:style 'code-inset]{@verbatim{<body><h1>Hello world</h1><p class="first">Nice to <i>see</i> you.</p></body>}}
@terminal{<body><h1>Hello world</h1><p class="first">Nice to <i>see</i> you.</p></body>}
An X-expression is just a simplified, generalized method of notation for these data structures — much like Markdown is a simplified method of notation for HTML. To see the relationship, we'll convert one into the other.
First, we change the angle brackets to parentheses, and only use them on the outside of tags:
@nested[#:style 'code-inset]{@verbatim{(body (h1 Hello world /h1) (p class="first" Nice to (i see /i) you. /p) /body)}}
@terminal{(body (h1 Hello world /h1) (p class="first" Nice to (i see /i) you. /p) /body)}
Then we get rid of the closing tags, which are superfluous, since the closing parenthesis marks the end of the tag perfectly well:
Then we get rid of the closing tags, which are superfluous, since each closing parenthesis adequately marks the end of the tag:
@nested[#:style 'code-inset]{@verbatim{(body (h1 Hello world) (p class="first" Nice to (i see) you.))}}
@terminal{(body (h1 Hello world) (p class="first" Nice to (i see) you.))}
However, this creates ambiguity between the name of the tag and the content. So we'll put the content within quote marks:
However, this creates ambiguity between the name of the tag and the content. So we'll put the content within double quotes:
@nested[#:style 'code-inset]{@verbatim{(body (h1 "Hello world") (p class="first" "Nice to" (i "see") "you."))}}
@terminal{(body (h1 "Hello world") (p class="first" "Nice to" (i "see") "you."))}
As for the @racketfont{class} attribute, we need to distinguish it from both the markup tags and the content, so we'll move it between double parentheses:
@nested[#:style 'code-inset]{@verbatim{(body (h1 "Hello world") (p ((class "first")) "Nice to" (i "see") "you."))}}
@terminal{(body (h1 "Hello world") (p ((class "first")) "Nice to" (i "see") "you."))}
Net of a few boring details, that's basically all there is to it.
So why is it called an X-expression? Lisp languages are built out of units called S-expressions, which look like this:
@nested[#:style 'code-inset]{@verbatim{(and (txexpr? x) (member (get-tag x) (project-block-tags)) #t))}}
@terminal{(and (txexpr? x) (member (get-tag x) (project-block-tags)) #t))}
S-expressions use prefix notation, where each pair of parentheses contains a list. The first element in the list names a function, and the other elements are the arguments to that function. (This is a review of @secref["Racket_basics__if_you_re_not_familiar_" #:doc '(lib "pollen/scribblings/pollen.scrbl")].) X-expressions are just a minor adaptation of S-expression notation to represent markup, hence the name (the @italic{X} is short for @italic{XML-like}).
@ -182,18 +191,20 @@ Let's start putting together our article. For simplicity, I'm going to use unrea
We want to use Markdown authoring mode to make a file that will ultimately be HTML. So consistent with Pollen file-naming conventions (see @secref["Saving___naming_your_source_file" #:doc '(lib "pollen/scribblings/pollen.scrbl")]), we'll start with our desired output filename, @racketfont{article.html}, and then append the Markdown authoring suffix, @racketfont{.pmd}. So in DrRacket, start a new file called @racketfont{article.html.pmd} and put some Markdown in it:
@filebox["article.html.pmd"]{@verbatim{
@fileblock["article.html.pmd"
@codeblock{
#lang pollen
Deep Thought
============
I am **so** happy to be writing this.}}
I am **so** happy to be writing this.
}]
Before you preview this file in the project server, click the @onscreen{Run} button in DrRacket just to see what the file produces. You'll see something like this:
@nested[#:style 'code-inset]{@racketvalfont{'(root (h1 ((id "my-article")) "Deep Thought") (p () "I am "
@(linebreak)(strong () "so") " happy to be writing this."))}}
@repl-output{'(root (h1 ((id "my-article")) "Deep Thought") (p () "I am "
(strong () "so") " happy to be writing this."))}
You should now be able to recognize this as an X-expression. In authoring mode, Pollen parses your Markdown into the corresponding HTML entities, but then provides the data as an X-expression rather than finished HTML.
@ -202,23 +213,30 @@ You should now be able to recognize this as an X-expression. In authoring mode,
From what you learned in the last section, it should be evident that this X-expression corresponds to HTML that looks like this:
@nested[#:style 'code-inset]{@racketvalfont{<root><h1 id="my-article">Deep Thought</h1><p>I am @(linebreak)<strong>so</strong> happy to be writing this.</p></root>}}
@repl-output{<root><h1 id="my-article">Deep Thought</h1><p>I am @(linebreak)<strong>so</strong> happy to be writing this.</p></root>}
``But what's this @racketfont{root} tag? That's not HTML.'' An X-expression must have a root tag, so in the spirit of obviousness, every X-expression produced by a source file in authoring mode will start with @racketfont{root}. If you don't need it, you can discard it. But it also creates a useful hook for further processing, as we'll see later.
By the way, as review, let's remind ourselves how this is different from preprocessor mode. Let's take the same Markdown content, but this time put it into a preprocessor source file called @racketfont{article.md.pp}.
@filebox["article.md.pp"]{@verbatim{
@fileblock["article.md.pp"
@codeblock{
#lang pollen
Deep Thought
============
I am **so** happy to be writing this.}}
I am **so** happy to be writing this.
}]
When you run this file in DrRacket, you'll see:
@nested[#:style 'code-inset]{@racketvalfont{Deep Thought@(linebreak)============@(linebreak)@(linebreak)I am **so** happy to be writing this.}}
@repl-output{
Deep Thought
============
I am **so** happy to be writing this.
}
Hopefully, this result makes sense to you: when you run Markdown source in preprocessor mode, you get Markdown. When you run Markdown source in authoring mode, you get an X-expression.
@ -236,29 +254,32 @@ The major difference with Pollen templates is that there's no special ``template
To see a template in action, let's return to the source file we started in the last section:
@filebox["article.html.pmd"]{@verbatim{
@fileblock["article.html.pmd"
@codeblock{
#lang pollen
Deep Thought
============
I am **so** happy to be writing this.}}
I am **so** happy to be writing this.
}]
Last time, I had you run this file in DrRacket to see the X-expression it produced. This time, load it in the project server. You'll see something like this:
@nested[#:style 'code-inset]{
@terminal{
@bold{@larger{@larger{Deep Thought}}}
I am @bold{so} happy to be writing this.
@larger{@smaller{I am @bold{so} happy to be writing this.}}
}
Here, you're seeing the X-expression from your source combined with an HTML template, which adds the necessary boilerplate for the finished HTML:
@nested[#:style 'code-inset]{@racketvalfont{
@repl-output{
<html><head><meta charset="UTF-8" /></head><body>
@(linebreak)<root><h1 id="my-article">Deep Thought</h1><p>I am
@(linebreak)<strong>so</strong> happy to be writing this.</p></root>
@(linebreak)</body></html>}}
<root><h1 id="my-article">Deep Thought</h1><p>I am
<strong>so</strong> happy to be writing this.</p></root>
</body></html>
}
But wait — where did the template come from? When you view an authoring-mode source file in the project server without specifying a template, Pollen helps you out and uses its @italic{fallback template}. The fallback template is just a minimal template that's used as a last resort. Under ordinary circumstances, seeing the fallback template usually signals a problem (e.g., Pollen couldn't find the template you asked for).
@ -268,25 +289,38 @@ But we can learn a few things from the fallback template about how to make an HT
This is the fallback template that Pollen uses.
@filebox["fallback.html"]{@verbatim{◊(->html (html (head (meta 'charset: "UTF-8")) (body doc)))}}
@fileblock["fallback.html"
@codeblock[#:keep-lang-line? #f]{
#lang pollen
◊(->html (html (head (meta 'charset: "UTF-8")) (body doc)))
}]
It has three key ingredients.
First, there's an X-expression that represents a basic HTML page:
@nested[#:style 'code-inset]{@verbatim{(html (head (meta 'charset: "UTF-8")) (body))}}
@codeblock[#:keep-lang-line? #f]{
#lang pollen
(html (head (meta 'charset: "UTF-8")) (body))
}
This is equivalent to the HTML:
@nested[#:style 'code-inset]{@verbatim{<html><head><meta charset="UTF-8"></head><body></body></html>}}
@terminal{<html><head><meta charset="UTF-8"></head><body></body></html>}
But within a template, we need to explicitly convert from X-expression to HTML. So we wrap this X-expression with our second key ingredient, the Pollen command @racket[->html]:
@nested[#:style 'code-inset]{@verbatim{◊(->html (html (head (meta 'charset: "UTF-8")) (body)))}}
@codeblock[#:keep-lang-line? #f]{
#lang pollen
◊(->html (html (head (meta 'charset: "UTF-8")) (body)))
}
Third, we need to include the content from our source file. We do this by putting the variable @racketfont{doc} inside the @racketfont{body} tag.
@nested[#:style 'code-inset]{@verbatim{◊(->html (html (head (meta 'charset: "UTF-8")) (body doc)))}}
@codeblock[#:keep-lang-line? #f]{
#lang pollen
◊(->html (html (head (meta 'charset: "UTF-8")) (body doc)))
}
By convention, every Pollen source file makes its output available through the variable @racketfont{doc}. A source file in preprocessor mode puts its text result in @racketfont{doc}. And a source file in authoring mode puts its X-expression result in @racketfont{doc}.
@ -298,8 +332,11 @@ Caution — despite the name, a Pollen template is not necessarily a file of the
It could be, however. Here's an equivalent way of writing @racketfont{fallback.html} that inserts @racketfont{doc} into actual HTML, rather than making the whole thing an X-expression.
@nested[#:style 'code-inset]{@verbatim{<html><head><meta charset="UTF-8"></head>
<body>◊(->html doc)</body></html>}}
@codeblock[#:keep-lang-line? #f]{
#lang pollen
<html><head><meta charset="UTF-8"></head>
<body>◊(->html doc)</body></html>
}
Notice that we still need to use the @racket[->html] function, but this time, instead of surrounding a larger X-expression, it just goes around @racketfont{doc}.
@ -316,17 +353,24 @@ Therefore, to set up a custom template, all we need to do is create a file calle
But don't take my word for it. In your project directory, create a new file called @racketfont{template.html}:
@filebox["template.html"]{@verbatim{<html>
@fileblock["template.html"
@codeblock[#:keep-lang-line? #f]{
#lang pollen
<html>
<head><meta charset="UTF-8">
<title>Custom template</title></head>
<body>◊(->html doc)</body>
</html>}}
</html>
}]
Recall from the last section that this is the same as the fallback template, but written out in HTML, and with a @racketfont{title} element added. In fact, you can now refresh @racketfont{article.html} in the project server. Does it look different? No — it won't, because the resulting template is the same. You should notice, however, that the title of the browser window is now ``Custom template,'' because Pollen is relying on your new template file, rather than the fallback template.
Let's change our custom template by adding a @racketfont{style} block:
@filebox["template.html"]{@verbatim{<html>
@fileblock["template.html"
@codeblock[#:keep-lang-line? #f]{
#lang pollen
<html>
<head><meta charset="UTF-8">
<title>Custom template</title>
<style type="text/css">
@ -335,7 +379,7 @@ h1 {background: gray; color: white;}
strong {color: red;}
</style></head>
<body>◊(->html doc)</body>
</html>}}
</html>}]
When you refresh @racketfont{article.html} in the project server, you'll see that the heading now has a gray background, and one word in the text is red.
@ -353,63 +397,80 @@ Let's suppose that we'd rather use the name of the article — @italic{Deep Tho
Beyond that, we just need to know the tag name that contains the title. If we have a little Markdown expertise, we might already know that this part of our Markdown source:
@verbatim{Deep Thought
============}
@codeblock[#:keep-lang-line? #f]{
#lang pollen
Deep Thought
============
}
is going to produce a tag named @racketfont{h1}.
What if we don't have all the Markdown conversions memorized? No problem. We can still figure out the tag name by running the @racketfont{article.html.pmd} source file in DrRacket and looking at the X-expression that results:
@nested[#:style 'code-inset]{@racketvalfont{'(root (h1 ((id "my-article")) "Deep Thought") (p () "I am "
@(linebreak)(strong () "so") " happy to be writing this."))}}
@repl-output{'(root (h1 ((id "my-article")) "Deep Thought") (p () "I am "
(strong () "so") " happy to be writing this."))}
Either way, now we know that the text @italic{Deep Thought} lives in the @racketfont{h1} tag. So we update our template accordingly (for brevity, I'm going to omit the @racketfont{style} tag in these examples, but it's fine to leave it in):
@filebox["template.html"]{@verbatim{<html>
@fileblock["template.html"
@codeblock[#:keep-lang-line? #f]{
#lang pollen
<html>
<head><meta charset="UTF-8">
<title>◊(select 'h1 doc)</title></head>
<body>◊(->html doc)</body>
</html>}}
</html>
}]
When you refresh the page in the project server, the page title will now appear as ``Deep Thought.'' Of course, you can also combine static and dynamic elements in your template, like so:
@filebox["template.html"]{@verbatim{<html>
@fileblock["template.html"
@codeblock[#:keep-lang-line? #f]{
#lang pollen
<html>
<head><meta charset="UTF-8">
<title>◊(select 'h1 doc), by MB</title></head>
<body>◊(->html doc)</body>
</html>}}
</html>
}]
The page title will now be ``Deep Thought, by MB''.
A couple notes on command syntax. We inserted the @racket[select] and @racket[->html] commands using Racket-mode syntax. We could also use text-mode syntax and write the commands this way:
@filebox["template.html"]{@verbatim{<html>
@fileblock["template.html"
@codeblock[#:keep-lang-line? #f]{
#lang pollen
<html>
<head><meta charset="UTF-8">
<title>◊select['h1 doc], by MB</title></head>
<body>◊->html[doc]</body>
</html>}}
</html>
}]
This is exactly equivalent to the previous example. Skeptics are welcome to confirm this by checking the result in the project server.
Finally, notice that in the @racket[select] command, the tag name @racket['h1] is written with a quote mark, whereas @racketfont{doc} is not. This is an easy place to get tripped up, but the rule is simple: you don't use a quote mark when you're referring to the name of an existing function or variable (like @racket[select] or @racketfont{doc}). But you do need a quote mark when you're using the text as a literal value.
@(require scribble/core)
@(define (racketfont* . args)
(element 'tt args))
@margin-note{Racket (and hence Pollen) makes a distinction between @secref["symbols" #:doc '(lib "scribblings/guide/guide.scrbl")] (e.g. @racket['h1]) and @secref["strings" #:doc '(lib "scribblings/reference/reference.scrbl")] (e.g. @racket["h1"]). Without getting into the weeds, just note for now that the tag of an X-expression is always a symbol, not a string. But if you write @racketfont{◊(select "h1" doc)}, the command will still work, because Pollen will treat it as @racketfont*{◊(select 'h1 doc)}, consistent with a general policy of not being persnickety about input types when the intention is clear.}
@margin-note{Racket (and hence Pollen) makes a distinction between @secref["symbols" #:doc '(lib "scribblings/guide/guide.scrbl")] (e.g. @racket['h1]) and @secref["strings" #:doc '(lib "scribblings/reference/reference.scrbl")] (e.g. @racket["h1"]). Without getting into the weeds, just note for now that the tag of an X-expression is always a symbol, not a string. But if you write @racketfont*{◊(@racket[select] "h1" doc)}, the command will still work, because Pollen will treat it as @racketfont*{◊(@racket[select] 'h1 doc)}, consistent with a general policy of not being persnickety about input types when the intention is clear.}
@subsection{Linking to an external CSS file}
If you're a super web hotshot, you probably don't put your CSS selectors in the @racketfont{<head>} tag. Instead, you link to an external CSS file. So it will not surprise you that in Pollen, you can do this by adding the usual @racketfont{<link>} tag to your HTML template, in this case a file called @racketfont{styles.css}:
@filebox["template.html"]{@verbatim{<html>
@fileblock["template.html"
@codeblock[#:keep-lang-line? #f]{
#lang pollen
<html>
<head><meta charset="UTF-8">
<title>◊select['h1 doc], by MB</title></head>
<link rel="stylesheet" type="text/css" media="all" href="styles.css" />
<body>◊->html[doc]</body>
</html>}}
</html>
}]
Fans of hand-coded CSS, I trust you to take it from here: make your @racketfont{styles.css} file, and enjoy the results.
@ -419,14 +480,17 @@ Yes, of course. Here's the rule of thumb: when you're making links between files
So to use a dynamic CSS file, we don't need to make any changes to @racketfont{template.html}. We just need to add @racketfont{styles.css.pp} to the project directory:
@filebox["styles.css.pp"]{@verbatim{#lang pollen
@fileblock["styles.css.pp"
@codeblock{
#lang pollen
◊(define h1-color "blue")
◊(define strong-color "green")
body {padding: 3em; font-size: 20px;}
h1 {background: ◊|h1-color|; color: white;}
strong {color: ◊|strong-color|;}}}
strong {color: ◊|strong-color|;}
}]
Now, when you refresh @racketfont{article.html} in the project server, Pollen will generate the @racketfont{styles.css} file it needs, and you'll see the new colors in the page. As before, if you update @racketfont{styles.css.pp}, Pollen will notice and regenerate the CSS file when you refresh the page.
@ -460,31 +524,37 @@ If the multiple pages in your project are already ordered by filename, then you
From earlier in the tutorial, you have a Markdown source file called @racketfont{article.html.pmd} that looks like this:
@filebox["article.html.pmd"]{@verbatim{
@fileblock["article.html.pmd"
@codeblock{
#lang pollen
Deep Thought
============
I am **so** happy to be writing this.}}
I am **so** happy to be writing this.
}]
Let's supplement this source file by creating two others for the project:
@filebox["barticle.html.pmd"]{@verbatim{
@fileblock["barticle.html.pmd"
@codeblock{
#lang pollen
Barticle Title
==============
The wonderful second part of the article.}}
The wonderful second part of the article.
}]
@filebox["carticle.html.pmd"]{@verbatim{
@fileblock["carticle.html.pmd"
@codeblock{
#lang pollen
Carticle Title
==============
The terrific third part.}}
The terrific third part.
}]
As before, you can fill these source files with any sample Markdown content you like. Moreover, you don't have to use the filenames @racketfont{barticle.html.pmd} and @racketfont{carticle.html.pmd} — the point is that the intended sequence needs to match the alphabetic sorting of the filenames.
@ -511,20 +581,27 @@ To make any navigation link — up, down, sideways — the general idea is that
First, let's just see @racketfont{here} on its own. Update your template as follows:
@filebox["template.html"]{@verbatim{<html>
@fileblock["template.html"
@codeblock[#:keep-lang-line? #f]{
#lang pollen
<html>
<head><meta charset="UTF-8">
<title>◊select['h1 doc], by MB</title></head>
<link rel="stylesheet" type="text/css" media="all" href="styles.css" />
<body>◊->html[doc]
The current page is called ◊|here|.
</body>
</html>}}
</html>
}]
If you refresh @racketfont{article.html}, you will now see the line ``The current page is called article.html.'' Switch to @racketfont{barticle.html}, and you'll see ``The current page is called barticle.html.'' Makes sense, right?
Now let's use pagetree functions to show the names of the previous and next pages. Consistent with the usual policy of obviousness, these functions are called @racket[previous] and @racket[next]:
@filebox["template.html"]{@verbatim{<html>
@fileblock["template.html"
@codeblock[#:keep-lang-line? #f]{
#lang pollen
<html>
<head><meta charset="UTF-8">
<title>◊select['h1 doc], by MB</title></head>
<link rel="stylesheet" type="text/css" media="all" href="styles.css" />
@ -533,13 +610,17 @@ The current page is called ◊|here|.
The previous is ◊|(previous here)|.
The next is ◊|(next here)|.
</body>
</html>}}
</html>
}]
Refresh @racketfont{barticle.html}. You'll now see that ``The current page is called barticle.html. The previous is article.html. The next is carticle.html.'' So far, so good: we're correctly deriving the previous and next pages from the automatic pagetree.
All that's left is to add hyperlinks, which is easy:
@filebox["template.html"]{@verbatim{<html>
@fileblock["template.html"
@codeblock[#:keep-lang-line? #f]{
#lang pollen
<html>
<head><meta charset="UTF-8">
<title>◊select['h1 doc], by MB</title></head>
<link rel="stylesheet" type="text/css" media="all" href="styles.css" />
@ -548,7 +629,8 @@ The current page is called ◊|here|.
The previous is <a href="◊|(previous here)|">◊|(previous here)|</a>.
The next is <a href="◊|(next here)|">◊|(next here)|</a>.
</body>
</html>}}
</html>
}]
Refresh @racketfont{barticle.html}, and you'll see that the names of the previous and next pages are now hyperlinks to those pages. Click through and convince yourself that it works.
@ -564,49 +646,64 @@ But since we have a whole programming language available in Pollen, that's a dul
To handle @racketfont{article.html}, we want to hide the previous-page navigation link when there's no previous page. As it turns out, if the @racket[previous] function can't find a previous page, it will return false. So we just need to wrap our previous-page navigation in the @racket[when/block] command like so:
@filebox["template.html"]{@verbatim{<html>
@fileblock["template.html"
@codeblock[#:keep-lang-line? #f]{
#lang pollen
<html>
<head><meta charset="UTF-8">
<title>◊select['h1 doc], by MB</title></head>
<link rel="stylesheet" type="text/css" media="all" href="styles.css" />
<body>◊->html[doc]
The current page is called ◊|here|.
◊when/block[(previous here)]{The previous is <a href="◊|(previous here)|">◊|(previous here)|</a>.}
◊when/block[(previous here)]{The previous is
<a href="◊|(previous here)|">◊|(previous here)|</a>.}
The next is <a href="◊|(next here)|">◊|(next here)|</a>.
</body>
</html>}}
</html>
}]
The basic structure of @racket[when/block] is @racketfont{◊when/block[@racketvarfont{condition}]{@racketvarfont{insert-this-text}}.} Note the square braces around the @racketvarfont{condition}, and the curly braces around the @racketvarfont{text}. Using @racketfont{(previous here)} as the condition is shorthand for ``when @racketfont{(previous here)} does not return false...''
The basic structure of @racket[when/block] is @racketfont{◊when/block[@racketvarfont{condition}]{@racketvarfont{insert-this-text}}.} Note the square braces around the @racketvarfont{condition}, and the curly braces around the @racketvarfont{text}. Using @racket[(previous here)] as the condition is shorthand for ``when @racket{(previous here)} does not return false...''
Programmers in the audience might be getting anxious about the repeated use of @racketfont{(previous here)} — you're welcome to store that value in a variable, and everything will work the same way:
Programmers in the audience might be getting anxious about the repeated use of @racket[(previous here)] — you're welcome to store that value in a variable, and everything will work the same way:
@filebox["template.html"]{@verbatim{<html>
@fileblock["template.html"
@codeblock[#:keep-lang-line? #f]{
#lang pollen
<html>
<head><meta charset="UTF-8">
<title>◊select['h1 doc], by MB</title></head>
<link rel="stylesheet" type="text/css" media="all" href="styles.css" />
<body>◊->html[doc]
The current page is called ◊|here|.
◊(define prev-page (previous here))
◊when/block[prev-page]{The previous is <a href="◊|prev-page|">◊|prev-page|</a>.}
◊when/block[prev-page]{The previous is
<a href="◊|prev-page|">◊|prev-page|</a>.}
The next is <a href="◊|(next here)|">◊|(next here)|</a>.
</body>
</html>}}
</html>
}]
We need a different technique for handling the end of the next-page navigation, because we're not reaching the actual end of the pagetree. We're just reaching the end of the pages we care about navigating through.
What condition will help us detect this? Here, we can notice that the names of our article pages all contain the string @racketfont{article}. While you'd probably want a more robust condition for a real project, in this tutorial, what we'll do is hide the next-page navigation if the name of the next page doesn't contain ``@racketfont{article}''. As we did before, we wrap our navigation line in the @racket[when/block] function:
@filebox["template.html"]{@verbatim{<html>
@fileblock["template.html"
@codeblock[#:keep-lang-line? #f]{
#lang pollen
<html>
<head><meta charset="UTF-8">
<title>◊select['h1 doc], by MB</title></head>
<link rel="stylesheet" type="text/css" media="all" href="styles.css" />
<body>◊->html[doc]
The current page is called ◊|here|.
◊(define prev-page (previous here))
◊when/block[prev-page]{The previous is <a href="◊|prev-page|">◊|prev-page|</a>.}
◊when/block[prev-page]{The previous is
<a href="◊|prev-page|">◊|prev-page|</a>.}
◊when/block[(regexp-match "article" (->string (next here)))]{
The next is <a href="◊|(next here)|">◊|(next here)|</a>.}
</body>
</html>}}
</html>
}]
This time, the condition is @racket[(regexp-match "article" (->string (next here)))]. How were you supposed to know this? You weren't. That's why this is a tutorial. Without going on a lengthy detour, the @racket[regexp-match] function returns true if the first string (in this case, @racket["article"]) is found inside the second string (in this case, we convert @racket[(next here)] to a string by wrapping it in @racket[->string]).
@ -620,29 +717,31 @@ Pagetree source files have a different syntax and status than other Pollen sourc
So let's make an @racketfont{index.ptree} file. At its simplest, a pagetree file can just be a list of files in the intended order. In DrRacket, create a new file in your project directory as follows:
@filebox["index.ptree"]{@verbatim{
@fileblock["index.ptree"
@codeblock{
#lang pollen
carticle.html
article.html
barticle.html
}}
}]
Now run the file. The result will be:
@nested[#:style 'code-inset]{@racketvalfont{'(pagetree-root carticle.html article.html barticle.html)}}
@repl-output{'(pagetree-root carticle.html article.html barticle.html)}
Pretty boring, I know. But behind the scenes, Pollen's pagetree parser is making sure your tree is valid (e.g., no duplicate or malformed names). Today it's boring, but on the day you have a long and complicated pagetree, you will be grateful.
Notice that the names in this pagetree are the names of @italic{output} files, not source files. This is deliberate, so that neither you nor Pollen has to care which files are static vs. dynamic. This next pagetree wouldn't be wrong in the sense of bad syntax — the pagetree parser won't complain — but it would be wrong in the sense of not-what-you-want, because it refers to source names rather than output names:
@filebox["bad-index.ptree"]{@verbatim{
@fileblock["bad-index.ptree"
@codeblock{
#lang pollen
carticle.html.pmd
article.html.pmd
barticle.html.pmd
}}
}]
You also probably noticed that the files are in a different order than they were in the automatic pagetree: @racketfont{carticle.html} is first, followed by @racketfont{article.html} and then @racketfont{barticle.html}. This too is deliberate, so we can see what happens with a differently ordered pagetree.
@ -654,19 +753,24 @@ BAM! An error page with a yellow box that says @racketfont{Cant convert #f to
So let's go back and fix that. Because we don't have extraneous files in our pagetree anymore, we can change the second conditional in the template to work the same way as the first:
@filebox["template.html"]{@verbatim{<html>
@fileblock["template.html"
@codeblock[#:keep-lang-line? #f]{
#lang pollen
<html>
<head><meta charset="UTF-8">
<title>◊select['h1 doc], by MB</title></head>
<link rel="stylesheet" type="text/css" media="all" href="styles.css" />
<body>◊->html[doc]
The current page is called ◊|here|.
◊(define prev-page (previous here))
◊when/block[prev-page]{The previous is <a href="◊|prev-page|">◊|prev-page|</a>.}
◊when/block[prev-page]{The previous is
<a href="◊|prev-page|">◊|prev-page|</a>.}
◊(define next-page (next here))
◊when/block[next-page]{
The next is <a href="◊|next-page|">◊|next-page|</a>.}
</body>
</html>}}
</html>
}]
Refresh @racketfont{barticle.html} — because you're updating the template, you don't need to restart the project server — and you'll see the right result. The previous-page link goes to @racketfont{article.html}, and the next-page link is hidden.

@ -1,94 +1,736 @@
#lang scribble/manual
@(require (for-label pollen/world))
@(require scribble/eval (for-label plot pollen/world pollen/tag racket/base pollen/template txexpr racket/list racket/string))
@(require "mb-tools.rkt")
@title[#:tag "tutorial-3"]{Third tutorial}
@(define my-eval (make-base-eval))
@(my-eval `(require pollen pollen/decode pollen/template pollen/tag xml racket/list txexpr))
In this tutorial, you'll use Pollen to publish a multi-page article written in Markdown. You'll learn about:
@title[#:tag "third-tutorial"]{Third tutorial}
Now you're getting to the good stuff. In this tutorial, you'll use Pollen to publish a multi-page article written in Pollen markup. You'll learn about:
@itemlist[
@item{Adding tags & attributes with Pollen markup}
@item{Attaching behavior to tag functions}
@item{the @racketfont{directory-require.rkt} file}
@item{@exec{raco pollen render} and @exec{raco pollen clone}}
]
If you want the shortest possible introduction to Pollen, try the @secref["quick-tour"].
@section[#:tag-prefix "tutorial-3"]{Prerequisites}
I'll assume you've completed the @secref["second-tutorial"] and that you understand the principles of Pollen authoring mode — creating source files, converting them to X-expressions, and then combining them with templates to make output files.
Because now it's time to pick up the pace. You've learned how to do some handy things with Pollen. But we haven't yet exploited the full fusion of writing environment and programming language. I promised you that @secref["The_book_is_a_program" #:doc '(lib "pollen/scribblings/pollen.scrbl")], right? So let's do some programming.
@section{Pollen markup vs. XML}
You can skip this section if XML holds no interest. But Pollen markup evolved out of my attempt to come up with an alternative to XML that would be more usable for writing. So if you're familiar with XML, the contrast may be helpful.
@subsection{The XML problem}
In the @secref["second-tutorial"], I made the case that Markdown is a limiting format for authors. Why? Markdown is essentially a notation system for HTML tags. As such, it has three problems: it's not semantic, it only covers a limited subset of HTML tags, and it can't be extended by an author.
These problems are partly limitations of HTML itself. And these limitations were meant to be cured by XML — the @italic{X} stands for @italic{extensible}. In principle, XML allows you to define whatever tags you like and use them in your document.
So why hasn't XML taken over the world? In practice, XML promises more than it delivers. The reasons are apparent to any writer who's attempted to use XML as an authoring format:
@itemlist[
@item{Sharing data between source files}
@item{@bold{Verbose syntax}. Unfortunately, XML relies on the same angle-bracket notation as HTML. If you think HTML source is hard to read, XML is even worse. Since much of writing involves reading, this feature is also a major bug.}
@item{@bold{Validation overhead}. Integral to XML is the concept of @italic{validation}, which guarantees that a document meets certain formal criteria, usually asserted in a @italic{schema}. To get the full value from XML, you generally want to use validation. But doing so imposes a lot more work on you as an author, and removes much of the expressive potential of XML.}
@item{@bold{Masochistic document processing}. I'm referring to XSLT, the preferred method of transforming XML documents. I know a little XSLT, so I'll concede that there's a method to its madness. But it's still madness.}
]
The nicest thing we could say about XML is that its intentions are good. It's oriented toward the right goals. But its benefits are buried under atrocious ergonomics.
@item{Meta and Doc}
@item(the project-require.rkt file)
@subsection{What Pollen markup does differently}
@item{Pagetrees}
Pollen markup can be seen as a way of reaping the benefits of XML without incurring the headaches. Like XML, Pollen markup allows you to freely tag your text. But unlike XML:
@itemlist[
@item{Pagetrees with raco pollen render}
@item{@bold{Simple syntax}. Pollen markup follows the usual conventions of Pollen commands.}
@item{@bold{No structural validation}. You can use any tags you want, in any order, and you needn't define them ahead of time. Your document will still work.}
@item{@bold{Racket processing}. Pollen markup tags can have behavior attached to them using Racket functions, either before you use them, or later.}
]
@subsection{Sharing data between preprocessor files}
The preprocessor is useful for inserting variables that hold values. But variables are only useful when they can be shared among multiple files. Let's look at one way to do that.
@subsection{``But I really need XML…''}
Any value in a Pollen file that's set up using @racket[define] can be pulled into another Pollen file using the @racket[require] function. For instance, let's set up another preprocessor file in the same directory as @racketfont["brennan.md.pp"], called @racketfont["dale.md.pp"]:
You can have XML. There's nothing wrong with using Pollen markup to generate XML files that can then be fed into an existing XML processing pipeline. In other words, using Pollen markup, you can treat XML as an output format rather than an input format.
@filebox["dale.md.pp"]{@verbatim{
In this tutorial, I'll be rendering Pollen markup with an HTML template. But you could easily use the same workflow with an XML template and thus end up with XML files.
@section{Writing with Pollen markup}
Pollen markup is a free-form markup system that lets you add arbitrary @italic{tags} and @italic{attributes} to your text. By arbitrary, I mean that they don't need to match up with an existing schema or specification (e.g., the tags permitted by HTML). They can — but that's an option, not a requirement.
I like to think of Pollen markup a way of capturing not just the text, but also my @bold{ideas about the text}. Some of these are low-level ideas (``this text should be italicized''). Some are high-level ideas (``this text is the topic of the page''). Some are just notes to myself. In short, everything I know about the text becomes part of the text.
In so doing, Pollen markup becomes the source code of the book. Let's try it out.
@subsection{Creating a Pollen markup file}
We're going to use Pollen markup to make a file that will ultimately be HTML. So consistent with the authoring-mode workflow we learned in the @secref["second-tutorial"], we'll start with our desired output filename, @racketfont{article.html}, and then append the Pollen markup suffix, @racketfont{.pm}.
In DrRacket, start a new file called @racketfont{article.html.pm} like so (BTW you can use any sample text you like):
@fileblock["article.html.pm" @codeblock{
#lang pollen
I want to attend RacketCon this year.
}]
My name is _Dale_, and I enjoy:
Consistent with usual authoring-mode policy, when you run this file, you'll get an X-expression that starts with @racketvalfont{root}:
+ super-duper boring sauce
@repl-output{'(root "I want to attend RacketCon this year.")}
+ at least 3 fish nuggets}}
Remember, even though the first line of the file is @racketmodfont{#lang} @racketmodname[pollen] — same as the last tutorial — the new @racketfont{.pm} suffix signals that Pollen should interpret the source as Pollen markup. Look what happens if you goof up and put Markdown source in a Pollen markup file, like so:
In the project server, this will produce the expected output:
@codeblock{
#lang pollen
I am **so** excited to attend __RacketCon__ this year.
}
@nested[#:style 'code-inset]{@verbatim{
My name is _Dale_, and I enjoy:
The Markdown syntax will be ignored, and pass through to the output:
+ super-duper boring sauce
@repl-output{'(root "I am **so** excited to attend __RacketCon__ this year.")}
+ at least 3 fish nuggets}}
Restore the non-Markdown source, and let's continue.
Now, let's update the content using values defined in @racketfont{brennan.md.pp}. We do this by adding the @racket[require] command to the top of our file:
@filebox["dale.md.pp"]{@verbatim{
@subsection{Tags & tag functions}
Pollen markup uses the same Pollen command syntax that we first saw in @secref["Adding_commands" #:doc '(lib "pollen/scribblings/pollen.scrbl")]. Previously, we used this command syntax to invoke functions like @racket[define] and @racket[->html]. Pollen markup is used to invoke a special kind of function called a @italic{tag function}, which is a function that, by default, adds a tag to the text.
To see how this works, restore your @racketfont{article.html.pm} file to its original state:
@codeblock{
#lang pollen
I want to attend RacketCon this year.
}
We can add any tag with Pollen markup, but for now, let's start with an old favorite: @racketvalfont{em}, which is used in HTML to add emphasis to text. We apply a tag by starting with the lozenge character (◊) followed by the tag name @racketvalfont{em}, followed by the text in curly braces, like so:
@fileblock["article.html.pm" @codeblock{
#lang pollen
I want to attend ◊em{RacketCon this year}.
}]
Run this file in DrRacket and see the X-expression that results:
@repl-output{'(root "I want to attend " (em "RacketCon this year") ".")}
You won't be surprised to hear that you can nest tags:
@fileblock["article.html.pm" @codeblock{
#lang pollen
I want to attend ◊em{RacketCon ◊strong{this} year}.}]
With the expected results:
@repl-output{'(root "I want to attend " (em "RacketCon " (strong "this") " year") ".")}
@subsection{Attributes}
◊(require "brennan.md.pp")
@italic{Attributes} are like tags for tags. Each attribute is a keyvalue pair where the key is any name, and the value is a string. Anyone who's seen HTML is familiar with them:
My name is _Dale_, and I enjoy:
@repl-output{<span class="author">Prof. Leonard</span>}
+ super-duper boring sauce
Here, @racketvalfont{class} is an attribute for @racketvalfont{span} that has value @racketvalfont{"author"}. And this is what it looks like as an X-expression:
+ at least 3 fish nuggets}}
@repl-output{'(span ((class "author")) "Prof. Leonard")}
The three values that we defined in @racketfont{brennan.md.pp} — @racketfont{sauce-type}, @racketfont{nugget-type}, and @racketfont{nugget-quantity} — will now be available in @racketfont{dale.md.pp} under the same names, so we can insert them into the Markdown in the same way:
You can add any number of attributes to a tag (first as an X-expression, then as HTML):
@filebox["dale.md.pp"]{@verbatim{
@repl-output{'(span ((class "author")(id "primary")(living "true")) "Prof. Leonard")}
@repl-output{<span class="author" id="primary" living="true">Prof. Leonard</span>}
In Pollen markup, attributes have the same logic, but a slightly different syntax. In keeping with the tag notation you just saw, the @racketvalfont{span} tag is added in the usual way:
@fileblock["article.html.pm" @codeblock{
#lang pollen
◊span{Prof. Leonard}}]
Then you have two options for adding attributes. The verbose way corresponds to how the attributes appear in the X-expression:
@fileblock["article.html.pm" @codeblock{
#lang pollen
◊span['((class "author")(id "primary")(living "true"))]{Prof. Leonard}
}]
Each keyvalue pair is in parentheses, and then the list of pairs is within parentheses, with a @racket[quote] (@litchar{'}) at the front that signals that the text should be used literally.
This involves some superfluous typing, however, so Pollen also supports an abbreviated syntax for attributes:
@fileblock["article.html.pm" @codeblock{
#lang pollen
◊span['class:"author" 'id:"primary" 'living:"true"]{Prof. Leonard}
}]
In this form, each attribute key starts with a quote mark @litchar{'} and ends with a colon @litchar{:}. As before, the attribute value is in quotation marks.
Both of these forms will produce the same X-expression:
@repl-output{'(span ((class "author")(id "primary")(living "true")) "Prof. Leonard")}
Now that you know how to make tags and attributes, you might wonder whether Pollen markup can be used as a quick & dirty HTML-notation system. Sure — for a quick & dirty project, why not. Recall that @secref["X-expressions" #:doc '(lib "pollen/scribblings/pollen.scrbl")] are just alternative notation for the standard angle-bracket notation used in HTML. So if you wanted HTML like this:
@repl-output{<div class="red" style="font-size:150%">Important <em>News</em></div>}
You could write it in Pollen markup like so:
@repl-output{◊div['class:"red" style:"font-size:150%"]{Important ◊em{News}}}
And then just convert it (using the @racket[->html] function) into the HTML above. Thus, the tags you already know and love (?) can be used in Pollen markup, but with fewer keystrokes and cruft.
Still, if Pollen markup were just an alternative notation system for HTML tags, it would be pretty boring. As I alluded above, that's merely a boring way to use it.
In the XML spirit, Pollen markup lets you use any tags you want. That's considerably less boring.
@subsection{What are custom tags good for?}
XML jocks can skip this section, since you already know. But if you've been mired in Markdown or HTML, read on.
Tags, broadly speaking, are a means of annotating a text with extra information, which I'll call @italic{metadata} (using that term in its generic sense, not in any fiddly computery way). Metadata is the key tool that enables an author to write a book with the benefits of @italic{semantic markup} and @italic{format independence}.
◊(require "brennan.md.pp")
@subsection{Semantic markup}
My name is _Dale_, and I enjoy:
@italic{Semantic markup} means adding metadata to text according to the meaning of the text, not merely its intended visual appearance. So rather than tagging @racketvalfont{RacketCon} with an @racketvalfont{em} tag, as we did above to indicate how the word should look, maybe we would tag it with an @racketvalfont{event} tag, to indicate what @italic{kind} of thing it is.
+ super-duper ◊sauce-type sauce
Semantic markup lets an author specify distinctions that would be ambiguous in pure visual terms, thereby capturing more meaning and intent. For instance, in books, italic styling is commonly applied to a number of unrelated types of information: emphasized words, movie titles, terms being used for the first time, headings, captions and labels, and so on. Under a non-semantic formatting scheme, perhaps one would tag them all @racketvalfont{em}. But in semantic terms, one would tag them @racketvalfont{movie-title}, @racketvalfont{first-use}, @racketvalfont{heading}, as appropriate.
+ at least ◊nugget-quantity ◊nugget-type nuggets}}
This has two major benefits. First, by separating appearance and meaning, an author can manage the content of the book in useful ways. For instance, if every movie title were tagged as @racketvalfont{movie-title} rather than @racketvalfont{italic}, then it would be simple to generate a list of all movies mentioned in the book (for the author's benefit) or a page index of movie references (for the reader's benefit). But without that semantic tagging, a movie title couldn't be distinguished from any other italicized text.
Reload the file in the project server, and you'll see the imported values:
@subsection{Format independence}
@nested[#:style 'code-inset]{@verbatim{
My name is _Dale_, and I enjoy:
The second benefit of custom tags is @italic{format independence}, or the ability to change the rendering of the text to suit a particular device or context.
+ super-duper fancy sauce
When a text is encrusted with format-specific visual tags — for instance, HTML tags — then the document markup is entangled with a single output format. If you only need one output format, fine.
+ at least 12 chicken nuggets}}
But increasingly, book authors have been called upon to publish their work in multiple formats: paper and PDF, but also web, e-book, or other natively digital formats, that connect to devices with differing display capabilities.
@margin-note{Yes, I know that many of these formats are based on variants of HTML. But the HTML you can use in a desktop web browser is quite different from, say, the HTML you can use in a Kindle .mobi file. The .mobi file has other technical requirements too, like an .ncx and .opf file. So despite some genetic kinship, these HTML-ish formats are best understood as separate targets.}
Using a display-driven model to manage this complexity is a terrible idea — as anyone who's tried it can attest. Converting from one display-based file type to another — for instance, word processor to HTML, or HTML to PDF — is an exercise in frustration and drain-circling expectations.
This isn't surprising. For a long time, text processing has been dominated by this display-driven model. Most word processors, like Microsoft Word and Pages, have been built around this model. It worked well enough in the era where most documents were eventually going to be printed on paper (or a paper simulator like PDF). HTML was a technical leap forward, but not a conceptual leap: it mostly represented the display options available in a web browser.
@margin-note{There's a couple TeX fans at the back of the room, waving their arms. Yes, TeX got a lot of things right. In practice, however, it never became a core tool for electronic publishing (which, to be fair, didn't exist when TeX was written). Plenty of ideas in Pollen were lifted from TeX.}
For a document to be format independent, two conditions have to be satisfied.
First, the document has to be readable by other programs, so they can handle the conversion of format-independent markup into a format-specific rendering (e.g., mapping semantic tags like @racketvalfont{movie-title} onto visual tags like @racketvalfont{em}). Most word-processor formats, like Word's .docx, are bad for authoring because these formats are opaque and proprietary. We needn't get into the political objections. As a practical matter, they're inarguably restrictive — if you can't get your data out of your file, you're stuck.
Second, the document itself has to be represented in a way that's independent of the particularities of any one format. For instance, HTML is a bad authoring format because it encourages authors to litter their text with HTML-isms like @racketvalfont{h1} and @racketvalfont{span}. These have no meaning outside of HTML, and thus will always cause conversion problems. The @seclink["Prelude__my_principled_objection_to_Markdown"
#:doc '(lib "pollen/scribblings/pollen.scrbl")]{same goes for Markdown}, which is simply HTML in disguise.
The solution to the first condition is to use text-based markup rather than proprietary file types. The solution to the second condition is to let authors define custom tags for the document, rather than the other way around. Pollen markup incorporates both of these ideas.
@subsection{Using custom tags}
You can insert a custom tag using the same syntax as any other tag. Suppose you want to use an @racketvalfont{event} tag to mark events. You would insert it like so:
@fileblock["article.html.pm" @codeblock{
#lang pollen
I want to attend ◊event{RacketCon} this year.}]
This markup will turn into this X-expression:
@repl-output{'(root "I want to attend " (event "RacketCon") " this year.")}
Which is equivalent to this XML:
@repl-output{<root>I want to attend <event>RacketCon</event> this year.</root>}
In truth, Pollen doesn't notice any difference between a custom tag vs. a standard HTML tag vs. any other kind of tag. They're all just markup tags. If you want to restrict yourself to a certain vocabulary of tags, you can. If you want to set up Pollen to enforce those restrictions, you can do that too. But by default, Pollen doesn't impose restrictions like this. In general, you can pick any tag name you want, and it will work.
Don't take my word for it. See what happens if you write this:
@fileblock["article.html.pm" @codeblock{
#lang pollen
I want to attend ◊verylongandimpracticaltagname{RacketCon} this year.}]
One small but important exception to this rule. If you were wondering why I sometimes call them @italic{tag functions} instead of just @italic{tags}, it's because under the hood, every tag is implemented as a function. The default behavior of this function is just to wrap the text in a tag with the given name.
The benefit of treating tags as functions will become evident later in this tutorial. But the cost of this approach is that tags occupy the same namespace as the other functions available in Pollen (and by extension, Racket). So if you try to use a tag name that's already the name of an existing function, an error will occur.
For instance, let's suppose you try to use a custom tag called @racketvalfont{length}:
@fileblock["article.html.pm" @codeblock{
#lang pollen
The Panama Canal is ◊length{77km} across.}]
When you run this file, you get an error:
@errorblock{length: contract violation;
expected: list?
  given: "77km"}
The problem is that Racket already provides a function called @racket[length]. Consistent with the usual rules of Pollen command notation, your command is interpreted as an attempt to invoke the @racket[length] function, rather than apply a tag named @racketvalfont{length}.
In practice, namespace clashes are rare. But if necessary, they're easy to work around (for the simplest method, see @secref["Invoking_tag_functions"
#:doc '(lib "pollen/scribblings/pollen.scrbl")]).
@subsection{Choosing custom tags}
You just saw that using custom tags is easy. Choosing custom tags, on the other hand, is less science than art. As the author, it's up to you. Some guidelines:
@itemlist[
@item{@bold{You're never doing it wrong.} I wanted to make sure you knew the case for semantic markup. But if your life would be easier just using HTML tags directly, go ahead.}
@item{@bold{Tag iteratively.} Don't worry about getting all your tags right the first time through. Just as you write and then rewrite, add the tags that seem right now, and change or augment them later, because …}
@item{@bold{Tags emerge from writing.} It's hopeless to try to specify all your tags in advance. As you write, you'll learn things about the text, which will suggest new tags.}
@item{@bold{The best tag system is the one you'll stick with.} Tags aren't free. It takes effort to insert them consistently. Don't bother with an overambitious tag scheme that bores you more than it helps.}
@item{@bold{For boilerplate, tags are faster than text.} If you find yourself repeatedly formatting certain text in a certain way — for instance, lists and tables — extract the content and wrap it in a tag that encapsulates the boilerplate.}
]
And most important:
@itemlist[
@item{@bold{Tags are functions.} As I @seclink["Tags___tag_functions"
#:doc '(lib "pollen/scribblings/pollen.scrbl")]{mentioned above}, every tag has a function behind it that uses the content of the tag as input. The default tag function just outputs the tag and its content. But you can replace this with any kind of function. So in practice, you can offload a lot of labor to tags. }
]
As we'll see in the next section, this is where your book truly becomes programmable.
@section{Tags are functions}
@(noskip-note)
If you've used HTML or XML, tags are just tags: things you type into the document that look the same going out as they did going in. Tags can be used to select document elements or assign styling (via CSS). But they don't have any deeper effect on the document content.
That's not so in Pollen. Under the hood, Pollen is just an alternate way of writing code in the Racket programming language. And tags, instead of being inert markers, are actually functions.
I think most of you know what a function is, but just to be safe — in programming, a @italic{function} is a chunk of code that accepts some input, processes it, and then returns a value. Asking a function to process some data is known as @italic{calling} the function.
Leading us to the Three Golden Rules of Pollen Tags:
@itemlist[#:style 'ordered
@item{@bold{Every Pollen tag calls a function with the same name.}}
@item{@bold{The input values for that function are the attributes and content of the tag.}}
@item{@bold{The whole tag — tag name, attributes, and content — is replaced with the return value of the called function.}}
]
You've already seen the simplest kind of function in a Pollen document: the @seclink["Tags___tag_functions"
#:doc '(lib "pollen/scribblings/pollen.scrbl")]{default tag function}, which emulates the behavior of standard markup tags.
Let's revisit an earlier example, now with the help of the Golden Rules:
@fileblock["article.html.pm" @codeblock{
#lang pollen
I want to attend ◊em{RacketCon ◊strong{this} year}.}]
What happens when you run this source? Working from the inside out, Pollen calls the function @racketvalfont{strong} with the input @racketvalfont{"this"}. The result is @racketvalfont{(strong "this")}. Then Pollen calls the function @racketvalfont{em} with the three input values @racketvalfont{"RacketCon " (strong "this") " year"}, which yields @racketvalfont{(em "RacketCon " (strong "this") " year")}. Finally, Pollen calls the @racketvalfont{root} function with everything in the document, resulting in:
@repl-output{'(root "I want to attend " (em "RacketCon " (strong "this") " year") ".")}
@subsection{Attaching behavior to tags}
Sometimes this default behavior will suffice. But other times, you'll want to change the behavior of a tag. Why? Here are some useful examples of what you, as an author, can do with custom tag functions:
@itemlist[
@item{Automatically detect cross-references and add hyperlinks.}
@item{Pull in data from an external source.}
@item{Generate tables, figures, and other fiddly layout objects.}
@item{Change content based on given conditions.}
@item{Automatically detect line breaks, paragraphs, and lists.}
@item{Insert boilerplate text.}
@item{Anything annoying or repetitive.}
@item{Mathematical computations.}
@item{… and anything else you like to do with a programming language.}
]
@margin-note{Having invited you to gaze across these vistas, I apologize that my example here in this tutorial is necessarily tip-of-the-iceberg. I'll be adding a more detailed guide to writing Pollen functions, both simple and crafty.}
How do you change the behavior of a tag? By 1) writing a new function and 2) giving it the name of the tag. Once you do this, this new behavior will automatically be invoked when you use the tag.
For example, let's redefine the @racketvalfont{strong} tag in our example above to simply print @racketvalfont{BOOM}:
@fileblock["article.html.pm" @codeblock{
#lang pollen
◊define[(strong . lines)]{BOOM}
I want to attend ◊em{RacketCon ◊strong{this} year}}]
When you run this file, you indeed get:
@repl-output{'(root "I want to attend " (em "RacketCon " "BOOM" " year"))}
How does this work? First, although you can define a function in Pollen command syntax using either of @secref["The_two_command_modes__text_mode___Racket_mode"
#:doc '(lib "pollen/scribblings/pollen.scrbl")], it tends to be easier to use Racket mode. I wrote the first one in text mode. But for clarity, I'm going to switch to Racket mode (run this file and convince yourself it comes out the same):
@fileblock["article.html.pm" @codeblock{
#lang pollen
◊(define (strong word) "BOOM")
I want to attend ◊em{RacketCon ◊strong{this} year}.}]
Let's look at our new function definition. As usual, we start with the lozenge character (@litchar{◊}) to denote a Pollen command. Then we use @racket[define] to introduce a function definition. The name of the function comes next, which needs to match our tag name, @racketvalfont{strong}. The expression @racket[(strong word)] means ``the name of this function is @racket[strong], and it takes a single word as input, which we'll refer to as @racket[word].'' Finally we have the return value, which is @racket["BOOM"].
Let's run this file again, but go back to the Golden Rules to understand what happens. Working from the inside out, Pollen calls the function @racketvalfont{strong} with the input @racketvalfont{"this"} — same as before. But this time, the result of the @racket[strong] function is not @racketvalfont{(strong "this")}, but simply @racketvalfont{BOOM}. Then Pollen calls the function @racketvalfont{em} with the three input values @racketvalfont{"RacketCon " "BOOM" " year"}, which yields @racketvalfont{(em "RacketCon " "BOOM" " year")}. Finally, Pollen calls the @racketvalfont{root} function with everything in the document, resulting in:
@repl-output{'(root "I want to attend " (em "RacketCon " "BOOM" " year"))}
This example is contrived, of course. But the basic idea — defining a function with the name of a tag — is the foundation of programmability in Pollen. @bold{If you get this, and the Golden Rules, you get everything.}
@subsection{Notes for experienced programmers}
Having said that, some of you are probably eager to hack around a bit. Let me chip off a few more cubes from the iceberg to help you on your way. (Everyone else, take five.)
@subsubsection{Point of no @code{return}} If you've written functions in other programming languages, you might be accustomed to using a @code{return} statement to send a value back from the function. This doesn't exist in Pollen or Racket — the return value of any function is just the last expression evaluated. In the example below, @racketvalfont{"BAP"} becomes the return value because it's in the last position, and @racketvalfont{"BOOM"} is ignored:
@fileblock["article.html.pm" @codeblock{
#lang pollen
◊(define (strong word) "BOOM" "BAP")
I want to attend ◊em{RacketCon ◊strong{this} year}.}]
@subsubsection{Multiple input values & rest arguments} Sometimes a tag will have only one word or string that becomes its input. More likely, however, it will have multiple values (this is inevitable with nested tags, because the results aren't concatenated). For instance, if we attach our function to @racket[em] rather than @racket[strong]:
@fileblock["article.html.pm" @codeblock{
#lang pollen
◊(define (em word) "BOOM")
I want to attend ◊em{RacketCon ◊strong{this} year}.}]
Look what happens:
@errorblock{
em: arity mismatch;
the expected number of arguments does not match the given number
expected: 1
  given: 3
}
The error arises because the @racket[em] function is getting three arguments — @racketvalfont{"RacketCon " "BOOM" " year"} — but has been defined to only accept one argument, @racket[word]. This is the ``arity mismatch.''
To fix this, it's better to get in the habit of writing tag functions that accept an indefinite number of input values. You do this by defining your function with a @italic{@seclink["contracts-rest-args" #:doc '(lib "scribblings/guide/guide.scrbl")]{rest argument}} (as in, ``give me the rest of the input values.'') To use a rest argument, put it last in your list of input arguments, and add a period @litchar{.} before:
@fileblock["article.html.pm" @codeblock{
#lang pollen
◊(define (em . parts) "BOOM")
I want to attend ◊em{RacketCon ◊strong{this} year}.}]
This time, the source file will run without an error, producing this:
@repl-output{'(root "I want to attend " "BOOM" ".")}
A rest argument like @racket[parts] is a @racket[list] of individual arguments. So if you want to unpack & process these arguments separately, you can use Racket's extensive list-processing functions (see @secref["pairs" #:doc '(lib "scribblings/guide/guide.scrbl")]). Also see @racket[quasiquote] below.
@subsubsection{Returning an X-expression} Often, you won't use a tag function to replace a whole tag with a string — you'll replace it with a different tag, described by an X-expression, like so:
@fileblock["article.html.pm" @codeblock{
#lang pollen
◊(define (em . parts) '(big "BOOM"))
I want to attend ◊em{RacketCon ◊strong{this} year}.}]
Which produces:
@repl-output{'(root "I want to attend " (big "BOOM") ".")}
The @racket[quote] mark @litchar{'} before the X-expression signals to Racket that you want to use what follows as a literal value.
To build X-expressions that are more elaborate, you have two options.
First is @racket[quasiquote]. Quasiquote works like quote, but starts with a backtick character @litchar{`}. What makes it ``quasi'' is that you can insert variables using the @racket[unquote] operator, which is a comma @litchar{,} or merge a list of values with the @racket[unquote-splicing] operator, which is a comma followed by an @"@" sign @litchar{,@"@"}.
Let's adapt the example above to use @racket[quasiquote]. Suppose we want to take the @racket[parts] we get as input and put them inside a @racket[big] tag. This is easy to notate with @racket[quasiquote] and the @racket[unquote-splicing] operator, because @racket[parts] is a list:
@fileblock["article.html.pm" @codeblock{
#lang pollen
◊(define (em . parts) `(big ,@"@"parts))
I want to attend ◊em{RacketCon ◊strong{this} year}.}]
Which produces this:
@repl-output{'(root "I want to attend " (big "RacketCon " (strong "this") " year") ".")}
Of course you can also nest X-expressions in your return value:
@fileblock["article.html.pm" @codeblock{
#lang pollen
◊(define (em . parts) `(extra (big ,@"@"parts)))
I want to attend ◊em{RacketCon ◊strong{this} year}.}]
The second option for building X-expressions is to use the @other-doc['(lib "txexpr/scribblings/txexpr.scrbl")] library that's included with Pollen (see those docs for more information).
@subsubsection{Interpolating variables into strings} The usual way is to use the @racket[format] function:
@racket[(format "String with variable: ~a" variable-name)]
See the docs for @racket[format] and @racket[fprintf] for your options.
Be careful if you're working with integers and X-expressions — a raw integer is treated as a character code, not an integer string. Using @racket[format] is essential:
@examples[#:eval my-eval
(->html '(div "A raw integer indicates a character code: " 42))
(->html `(div "Use format to make it a string: " ,(format "~a" 42)))
]
@subsubsection{Parsing attributes}
Detecting attributes in an argument list can be tricky because a) the tag may or may not have attributes, b) those attributes may be in standard or abbreviated syntax. For this reason, Pollen provides a @racket[split-attributes] function (in the @racket[pollen/tag] librar) that you can use in custom tag functions to separate the attributes and elements:
@fileblock["article.html.pm" @codeblock{
#lang pollen
◊(require pollen/tag)
◊(define (em . parts)
(define-values (attributes elements) (split-attributes parts))
`(extra ,attributes (big ,@"@"elements)))
I want to attend ◊em['key: "value"]{RacketCon}.}]
This will move the @racket[elements] inside the @racket[big] tag, and attach the @racket[attributes] to the @racket[extra] tag:
@repl-output{'(root "I want to attend " (extra ((key "value")) (big "RacketCon")) ".")}
@section[#:tag-prefix "tutorial-3"]{Intermission}
That was a lot of heavy material. But it also covered the most essential idea in Pollen: that @bold{every tag is a function}. Congratulations on making it this far.
The good news is that the rest of this tutorial will feel more relaxed, as we put these new principles to work.
Sorry that this tutorial is longer than the others, but truly — this is the stuff that makes Pollen different. If you're not feeling enthusiastic by now, you should @link["http://www.buzzfeed.com/search?q=puppies"]{bail out}.
Otherwise, get ready to rock.
@section{Organizing functions}
In the tag-function examples so far, we've defined each function within the source file where we used it. This is fine for quick little functions.
But more often, you're going to want to use functions defined elsewhere, and store your own functions available so they're available to your source files.
@margin-note{For now, we're just invoking functions within a Pollen markup file. But as you'll see in the fourth tutorial, any function can be called from any kind of Pollen source file.}
@subsection{Using Racket's function libraries}
Any function in Racket's extensive libraries can be called by loading the library with the @racket[require] command, which will make all its functions and constants available with the usual Pollen command syntax:
@fileblock["article.html.pm" @codeblock{
#lang pollen
◊(require racket/math)
Pi is close to ◊|pi|.
The hyperbolic sine of pi is close to ◊(sinh pi).
}]
The result:
@repl-output{'(root "Pi is close to " 3.141592653589793 "." "\n" "The hyperbolic sine of pi is close to " 11.548739357257748 ".")}
One caveat — you're still in a Pollen markup file, so the return value of whatever function you call has to produce a string or an X-expression, so it can be merged into the document. @margin-note*{This is similar to the restriction introduced in the @seclink["Setting_up_a_preprocessor_source_file"
#:doc '(lib "pollen/scribblings/pollen.scrbl")]{first tutorial} where functions used in preprocessor files had to produce text.}
Pollen won't stop you from calling a function that returns an incompatible value, like @racket[plot], which returns a bitmap image:
@fileblock["article.html.pm" @codeblock{
#lang pollen
◊(require math plot)
Here's a sine wave:
◊(plot (function sin (- pi) pi #:label "y = sin(x)"))
}]
But it won't work when you try to run it in DrRacket or load it in the project server.
It would be fine, however, to call a different kind of @racket[plot] function that returned an SVG result, because any XML-ish data structure can be converted to an X-expression.
@margin-note{Super web nerds also know that binary data can be converted into XML-ish form by encoding the file as a base-64 data URL — but if you know what I'm talking about, then you don't need my help to try it.}
For functions that don't return a string or an X-expression, you can always make a conversion by hand. For instance, consider @racket[range], a Racket function that returns a list of integers:
@fileblock["article.html.pm" @codeblock{
#lang pollen
◊(require racket/list)
A list of integers: ◊(range 5)
}]
This will produce an error in DrRacket:
@errorblock{
pollen markup error: in '(root "A list of integers: " (0 1 2 3 4)), '(0 1 2 3 4) is not a valid element (must be txexpr, string, symbol, XML char, or cdata)
}
In a case like this, you can explicitly convert the return value to a string (in whatever way makes sense):
@fileblock["article.html.pm" @codeblock{
#lang pollen
◊(require racket/list racket/string)
A list of integers: ◊(string-join (map number->string (range 5)))
}]
And get this output:
@repl-output{'(root "A list of integers: " "0 1 2 3 4")}
@subsection[#:tag-prefix "tutorial-3"]{The @racketfont{directory-require.rkt} file}
@(noskip-note)
As you get more comfortable attaching behavior to tags using tag functions, you'll likely want to create some functions that can be shared between multiple source files. The @racketfont{directory-require.rkt} file is a special file that is automatically imported by Pollen source files in the same directory. So every function and value provided by @racketfont{directory-require.rkt} can be used in these Pollen files.
First, using this file is not mandatory. You can always import functions and values from another file using @racket[require] (as seen in the previous section). The @racketfont{directory-require.rkt} is just meant to cure the tedium of importing the same file into every Pollen source file in your project. In a small project, not much tedium; in a large project, more.
Second, notice from the @racketfont{.rkt} suffix that @racketfont{directory-require.rkt} is a source file containing Racket code, not Pollen code. This is the default because while Pollen is better for text-driven source files, Racket is better for code-driven source files. Still, the choice is yours: the name of this file can be changed by resetting the @racket[world:directory-require] value.
Third, notice from the @racketfont{directory-} prefix that @racketfont{directory-require.rkt} is only used by Pollen source files @italic{in the same directory}. So if your project has source files nested inside a subdirectory, you'll need to explicitly create another @racketfont{directory-require.rkt} there and share the functions & values as needed.
@margin-note{``Why not make this file visible throughout a project, rather than just a directory?'' Good idea, but I couldn't figure out how to do it without creating finicky new dependencies. If you have a better idea, I'm open to it.}
Let's see how this works in practice. In the same directory as @racketfont{article.html.pm}, create a new @racketfont{directory-require.rkt} file as follows:
@fileblock["directory-require.rkt" @codeblock{
#lang racket
(define author "Trevor Goodchild")
(provide author)
}]
Here we use the @racket[define] function (which we've seen before) to set @racket[author] equal to @racket["Trevor Goodchild"]. Note the final step: consistent with standard Racket rules, we have to explicitly @racket[provide] the new value so that other files can see it (unlike Python, things you @racket[define] in Racket are private by default, not public).
Then update good old @racketfont{article.html.pm}:
@fileblock["article.html.pm" @codeblock{
#lang pollen
The author is ◊|author|.
}]
Run this in DrRacket and you'll get:
@repl-output{'(root "The author is " "Trevor Goodchild" ".")}
Now, in the same dirctory, create a second Pollen source file:
@fileblock["barticle.html.pm" @codeblock{
#lang pollen
The author is really ◊|author|?
}]
Run this, and you'll get:
@repl-output{'(root "The author is really " "Trevor Goodchild" "?")}
That's all there is to it. Everything provided by @racketfont{directory-require.rkt} is automatically available within each Pollen source file.
You can include functions, including tag functions, the same way. For instance, add a function for @racket[em]:
@fileblock["directory-require.rkt" @codeblock{
#lang racket
(define author "Trevor Goodchild")
(define (em . parts) `(extra (big ,@"@"parts)))
(provide author em)
}]
Then use it in a source file:
@fileblock["article.html.pm" @codeblock{
#lang pollen
@margin-note{Those familiar with Racket know that Racket makes you explicitly @racket[provide] any variables you want to export. To make life simpler, Pollen inverts this behavior and automatically exports all defined symbols using @racket[(provide (all-defined-out))]. For more about the differences in behavior between Racket and Pollen, see @secref["File_formats" #:doc '(lib "pollen/scribblings/pollen.scrbl")].}
The ◊em{author} is ◊em{◊|author|}.
}]
With the expected results:
@repl-output{'(root "The " (extra (big "author")) " is " (extra (big "Trevor Goodchild")) ".")}
@;subsection{Importing from a Pollen source file}
@;subsection{Making a Racket package}
@section{Putting it all together}
[Coming soon]
@;section{
1 directory-require.rkt
2-4 three source files
5 pagetree
6 template
}

@ -25,11 +25,11 @@ A parameter that sets the HTTP port for the project server. Initialized to @rack
)]
The two exports from a compiled Pollen source file. Initialized to @racket['doc] and @racket['metas], respectively.
@(defthing world:project-require string?)
File implicitly required into every Pollen source file from its directory. Initialized to @racket["project-require.rkt"].
@(defthing world:directory-require string?)
File implicitly required into every Pollen source file from its directory. Initialized to @racket["directory-require.rkt"].
@defparam[world:check-project-requires-in-render? check? boolean?]{
A parameter that determines whether the @racket[world:project-require] file is checked for changes on every pass through @racket[render]. (Can be faster to turn this off if you don't need it.) Initialized to @racket[#t].}
@defparam[world:check-directory-requires-in-render? check? boolean?]{
A parameter that determines whether the @racket[world:directory-require] file is checked for changes on every pass through @racket[render]. (Can be faster to turn this off if you don't need it.) Initialized to @racket[#t].}
@defthing[world:server-extras-dir string?]
Name of directory where server support files live. Initialized to @racket["server-extras"].

Loading…
Cancel
Save