You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3 lines
218 KiB
HTML
3 lines
218 KiB
HTML
<!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>7 Third tutorial</title><link rel="stylesheet" type="text/css" href="scribble.css" title="default"/><link rel="stylesheet" type="text/css" href="racket.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"/><link rel="stylesheet" type="text/css" href="mb.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,"tocview_0");">▼</a></td><td></td><td><a href="index.html" class="tocviewlink" data-pltdoc="x">Pollen:<span class="mywbr"> </span> the book is a program</a></td></tr></table></div><div class="tocviewsublisttop" style="display: block;" id="tocview_0"><table cellspacing="0" cellpadding="0"><tr><td align="right">1 </td><td><a href="Installation.html" class="tocviewlink" data-pltdoc="x">Installation</a></td></tr><tr><td align="right">2 </td><td><a href="quick-tour.html" class="tocviewlink" data-pltdoc="x">Quick tour</a></td></tr><tr><td align="right">3 </td><td><a href="Backstory.html" class="tocviewlink" data-pltdoc="x">Backstory</a></td></tr><tr><td align="right">4 </td><td><a href="big-picture.html" class="tocviewlink" data-pltdoc="x">The big picture</a></td></tr><tr><td align="right">5 </td><td><a href="first-tutorial.html" class="tocviewlink" data-pltdoc="x">First tutorial</a></td></tr><tr><td align="right">6 </td><td><a href="second-tutorial.html" class="tocviewlink" data-pltdoc="x">Second tutorial</a></td></tr><tr><td align="right">7 </td><td><a href="third-tutorial.html" class="tocviewselflink" data-pltdoc="x">Third tutorial</a></td></tr><tr><td align="right">8 </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 </td><td><a href="File_formats.html" class="tocviewlink" data-pltdoc="x">File formats</a></td></tr><tr><td align="right">10 </td><td><a href="reader.html" class="tocviewlink" data-pltdoc="x">◊ command overview</a></td></tr><tr><td align="right">11 </td><td><a href="Module_reference.html" class="tocviewlink" data-pltdoc="x">Module reference</a></td></tr><tr><td align="right">12 </td><td><a href="Acknowledgments.html" class="tocviewlink" data-pltdoc="x">Acknowledgments</a></td></tr><tr><td align="right">13 </td><td><a href="License___source_code.html" class="tocviewlink" data-pltdoc="x">License & 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 class="tocviewlist"><table cellspacing="0" cellpadding="0"><tr><td style="width: 1em;"><a href="javascript:void(0);" title="Expand/Collapse" class="tocviewtoggle" onclick="TocviewToggle(this,"tocview_1");">►</a></td><td>7 </td><td><a href="third-tutorial.html" class="tocviewselflink" data-pltdoc="x">Third tutorial</a></td></tr></table><div class="tocviewsublistbottom" style="display: none;" id="tocview_1"><table cellspacing="0" cellpadding="0"><tr><td align="right">7.1 </td><td><a href="third-tutorial.html#%28part._tutorial-3._.Prerequisites%29" class="tocviewlink" data-pltdoc="x">Prerequisites</a></td></tr><tr><td align="right">7.2 </td><td><a href="third-tutorial.html#%28part._.Pollen_markup_vs__.X.M.L%29" class="tocviewlink" data-pltdoc="x">Pollen markup vs. XML</a></td></tr><tr><td align="right">7.3 </td><td><a href="third-tutorial.html#%28part._.Writing_with_.Pollen_markup%29" class="tocviewlink" data-pltdoc="x">Writing with Pollen markup</a></td></tr><tr><td align="right">7.4 </td><td><a href="third-tutorial.html#%28part._.Tags_are_functions%29" class="tocviewlink" data-pltdoc="x">Tags are functions</a></td></tr><tr><td align="right">7.5 </td><td><a href="third-tutorial.html#%28part._tutorial-3._.Intermission%29" class="tocviewlink" data-pltdoc="x">Intermission</a></td></tr><tr><td align="right">7.6 </td><td><a href="third-tutorial.html#%28part._.Organizing_functions%29" class="tocviewlink" data-pltdoc="x">Organizing functions</a></td></tr><tr><td align="right">7.7 </td><td><a href="third-tutorial.html#%28part._.Decoding_markup_via_the_root_tag%29" class="tocviewlink" data-pltdoc="x">Decoding markup via the <span class="stt">root</span> tag</a></td></tr><tr><td align="right">7.8 </td><td><a href="third-tutorial.html#%28part._.Putting_it_all_together%29" class="tocviewlink" data-pltdoc="x">Putting it all together</a></td></tr><tr><td align="right">7.9 </td><td><a href="third-tutorial.html#%28part._.Third_tutorial_complete%29" class="tocviewlink" data-pltdoc="x">Third tutorial complete</a></td></tr></table></div></div></div><div class="tocsub"><div class="tocsubtitle">On this page:</div><table class="tocsublist" cellspacing="0"><tr><td><span class="tocsublinknumber">7.1<tt> </tt></span><a href="#%28part._tutorial-3._.Prerequisites%29" class="tocsubseclink" data-pltdoc="x">Prerequisites</a></td></tr><tr><td><span class="tocsublinknumber">7.2<tt> </tt></span><a href="#%28part._.Pollen_markup_vs__.X.M.L%29" class="tocsubseclink" data-pltdoc="x">Pollen markup vs. XML</a></td></tr><tr><td><span class="tocsublinknumber">7.2.1<tt> </tt></span><a href="#%28part._.The_.X.M.L_problem%29" class="tocsubseclink" data-pltdoc="x">The XML problem</a></td></tr><tr><td><span class="tocsublinknumber">7.2.2<tt> </tt></span><a href="#%28part._.What_.Pollen_markup_does_differently%29" class="tocsubseclink" data-pltdoc="x">What Pollen markup does differently</a></td></tr><tr><td><span class="tocsublinknumber">7.2.3<tt> </tt></span><a href="#%28part.__.But_.I_really_need_.X.M.L__%29" class="tocsubseclink" data-pltdoc="x">“But I really need XML…”</a></td></tr><tr><td><span class="tocsublinknumber">7.3<tt> </tt></span><a href="#%28part._.Writing_with_.Pollen_markup%29" class="tocsubseclink" data-pltdoc="x">Writing with Pollen markup</a></td></tr><tr><td><span class="tocsublinknumber">7.3.1<tt> </tt></span><a href="#%28part._.Creating_a_.Pollen_markup_file%29" class="tocsubseclink" data-pltdoc="x">Creating a Pollen markup file</a></td></tr><tr><td><span class="tocsublinknumber">7.3.2<tt> </tt></span><a href="#%28part._.Tags___tag_functions%29" class="tocsubseclink" data-pltdoc="x">Tags & tag functions</a></td></tr><tr><td><span class="tocsublinknumber">7.3.3<tt> </tt></span><a href="#%28part._.Attributes%29" class="tocsubseclink" data-pltdoc="x">Attributes</a></td></tr><tr><td><span class="tocsublinknumber">7.3.4<tt> </tt></span><a href="#%28part._.What_are_custom_tags_good_for_%29" class="tocsubseclink" data-pltdoc="x">What are custom tags good for?</a></td></tr><tr><td><span class="tocsublinknumber">7.3.5<tt> </tt></span><a href="#%28part._.Semantic_markup%29" class="tocsubseclink" data-pltdoc="x">Semantic markup</a></td></tr><tr><td><span class="tocsublinknumber">7.3.6<tt> </tt></span><a href="#%28part._.Format_independence%29" class="tocsubseclink" data-pltdoc="x">Format independence</a></td></tr><tr><td><span class="tocsublinknumber">7.3.7<tt> </tt></span><a href="#%28part._.Using_custom_tags%29" class="tocsubseclink" data-pltdoc="x">Using custom tags</a></td></tr><tr><td><span class="tocsublinknumber">7.3.8<tt> </tt></span><a href="#%28part._.Choosing_custom_tags%29" class="tocsubseclink" data-pltdoc="x">Choosing custom tags</a></td></tr><tr><td><span class="tocsublinknumber">7.4<tt> </tt></span><a href="#%28part._.Tags_are_functions%29" class="tocsubseclink" data-pltdoc="x">Tags are functions</a></td></tr><tr><td><span class="tocsublinknumber">7.4.1<tt> </tt></span><a href="#%28part._.Attaching_behavior_to_tags%29" class="tocsubseclink" data-pltdoc="x">Attaching behavior to tags</a></td></tr><tr><td><span class="tocsublinknumber">7.4.2<tt> </tt></span><a href="#%28part._.Notes_for_experienced_programmers%29" class="tocsubseclink" data-pltdoc="x">Notes for experienced programmers</a></td></tr><tr><td><span class="tocsublinknumber">7.4.2.1<tt> </tt></span><a href="#%28part._.Point_of_no_return%29" class="tocsubseclink" data-pltdoc="x">Point of no <span class="RktSym">return</span><span class="RktMeta"></span></a></td></tr><tr><td><span class="tocsublinknumber">7.4.2.2<tt> </tt></span><a href="#%28part._.Multiple_input_values___rest_arguments%29" class="tocsubseclink" data-pltdoc="x">Multiple input values & rest arguments</a></td></tr><tr><td><span class="tocsublinknumber">7.4.2.3<tt> </tt></span><a href="#%28part._.Returning_an_.X-expression%29" class="tocsubseclink" data-pltdoc="x">Returning an X-<wbr></wbr>expression</a></td></tr><tr><td><span class="tocsublinknumber">7.4.2.4<tt> </tt></span><a href="#%28part._.Interpolating_variables_into_strings%29" class="tocsubseclink" data-pltdoc="x">Interpolating variables into strings</a></td></tr><tr><td><span class="tocsublinknumber">7.4.2.5<tt> </tt></span><a href="#%28part._.Parsing_attributes%29" class="tocsubseclink" data-pltdoc="x">Parsing attributes</a></td></tr><tr><td><span class="tocsublinknumber">7.5<tt> </tt></span><a href="#%28part._tutorial-3._.Intermission%29" class="tocsubseclink" data-pltdoc="x">Intermission</a></td></tr><tr><td><span class="tocsublinknumber">7.6<tt> </tt></span><a href="#%28part._.Organizing_functions%29" class="tocsubseclink" data-pltdoc="x">Organizing functions</a></td></tr><tr><td><span class="tocsublinknumber">7.6.1<tt> </tt></span><a href="#%28part._.Using_.Racket_s_function_libraries%29" class="tocsubseclink" data-pltdoc="x">Using Racket’s function libraries</a></td></tr><tr><td><span class="tocsublinknumber">7.6.2<tt> </tt></span><a href="#%28part._tutorial-3._.Using_the_directory-require_rkt_file%29" class="tocsubseclink" data-pltdoc="x">Using the <span class="stt">directory-<wbr></wbr>require.rkt</span> file</a></td></tr><tr><td><span class="tocsublinknumber">7.7<tt> </tt></span><a href="#%28part._.Decoding_markup_via_the_root_tag%29" class="tocsubseclink" data-pltdoc="x">Decoding markup via the <span class="stt">root</span> tag</a></td></tr><tr><td><span class="tocsublinknumber">7.8<tt> </tt></span><a href="#%28part._.Putting_it_all_together%29" class="tocsubseclink" data-pltdoc="x">Putting it all together</a></td></tr><tr><td><span class="tocsublinknumber">7.8.1<tt> </tt></span><a href="#%28part._tutorial-3._.The_directory-require_rkt_file%29" class="tocsubseclink" data-pltdoc="x">The <span class="stt">directory-<wbr></wbr>require.rkt</span> file</a></td></tr><tr><td><span class="tocsublinknumber">7.8.2<tt> </tt></span><a href="#%28part._.The_template%29" class="tocsubseclink" data-pltdoc="x">The template</a></td></tr><tr><td><span class="tocsublinknumber">7.8.3<tt> </tt></span><a href="#%28part._.The_pagetree%29" class="tocsubseclink" data-pltdoc="x">The pagetree</a></td></tr><tr><td><span class="tocsublinknumber">7.8.4<tt> </tt></span><a href="#%28part._.A_.C.S.S_stylesheet_using_the_preprocessor%29" class="tocsubseclink" data-pltdoc="x">A CSS stylesheet using the preprocessor</a></td></tr><tr><td><span class="tocsublinknumber">7.8.5<tt> </tt></span><a href="#%28part._.The_content_source_files_using_.Pollen_markup%29" class="tocsubseclink" data-pltdoc="x">The content source files using Pollen markup</a></td></tr><tr><td><span class="tocsublinknumber">7.8.6<tt> </tt></span><a href="#%28part._.The_result%29" class="tocsubseclink" data-pltdoc="x">The result</a></td></tr><tr><td><span class="tocsublinknumber">7.9<tt> </tt></span><a href="#%28part._.Third_tutorial_complete%29" class="tocsubseclink" data-pltdoc="x">Third tutorial complete</a></td></tr></table></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> </span><span class="navright"> <a href="second-tutorial.html" title="backward to "6 Second tutorial"" data-pltdoc="x">← prev</a> <a href="index.html" title="up to "Pollen: the book is a program"" data-pltdoc="x">up</a> <a href="raco-pollen.html" title="forward to "8 Using raco pollen"" data-pltdoc="x">next →</a></span> </div><h3>7<tt> </tt><a name="(part._third-tutorial)"></a>Third tutorial</h3><p>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:</p><ul><li><p>Adding tags & attributes with Pollen markup</p></li><li><p>Attaching behavior to tag functions</p></li><li><p>the <span class="stt">directory-require.rkt</span> file</p></li><li><p>Using <span class="RktSym"><a href="Decode.html#%28def._%28%28lib._pollen%2Fdecode..rkt%29._decode%29%29" class="RktValLink" data-pltdoc="x">decode</a></span> with Pollen markup</p></li></ul><p>If you want the shortest possible introduction to Pollen, try the <a href="quick-tour.html" data-pltdoc="x">Quick tour</a>.</p><h4>7.1<tt> </tt><a name="(part._tutorial-3._.Prerequisites)"></a>Prerequisites</h4><p>I’ll assume you’ve completed the <a href="second-tutorial.html" data-pltdoc="x">Second tutorial</a> 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.</p><p>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 <a href="http://docs.racket-lang.org/pollen/big-picture.html#%28part._.The_book_is_a_program%29" data-pltdoc="x">The book is a program</a>, right? So let’s do some programming.</p><h4>7.2<tt> </tt><a name="(part._.Pollen_markup_vs__.X.M.L)"></a>Pollen markup vs. XML</h4><p>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.</p><h5>7.2.1<tt> </tt><a name="(part._.The_.X.M.L_problem)"></a>The XML problem</h5><p>In the <a href="second-tutorial.html" data-pltdoc="x">Second tutorial</a>, 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.</p><p>These problems are partly limitations of HTML itself. And these limitations were meant to be cured by XML — the <span style="font-style: italic">X</span> stands for <span style="font-style: italic">extensible</span>. In principle, XML allows you to define whatever tags you like and use them in your document.</p><p>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:</p><ul><li><p><span style="font-weight: bold">Verbose syntax</span>. 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.</p></li><li><p><span style="font-weight: bold">Validation overhead</span>. Integral to XML is the concept of <span style="font-style: italic">validation</span>, which guarantees that a document meets certain formal criteria, usually asserted in a <span style="font-style: italic">schema</span>. 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.</p></li><li><p><span style="font-weight: bold">Masochistic document processing</span>. 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.</p></li></ul><p>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.</p><h5>7.2.2<tt> </tt><a name="(part._.What_.Pollen_markup_does_differently)"></a>What Pollen markup does differently</h5><p>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:</p><ul><li><p><span style="font-weight: bold">Simple syntax</span>. Pollen markup follows the usual conventions of Pollen commands.</p></li><li><p><span style="font-weight: bold">No structural validation</span>. You can use any tags you want, in any order, and you needn’t define them ahead of time. Your document will still work.</p></li><li><p><span style="font-weight: bold">Racket processing</span>. Pollen markup tags can have behavior attached to them using Racket functions, either before you use them, or later.</p></li></ul><h5>7.2.3<tt> </tt><a name="(part.__.But_.I_really_need_.X.M.L__)"></a>“But I really need XML…”</h5><p>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.</p><p>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.</p><h4>7.3<tt> </tt><a name="(part._.Writing_with_.Pollen_markup)"></a>Writing with Pollen markup</h4><p>Pollen markup is a free-form markup system that lets you add arbitrary <span style="font-style: italic">tags</span> and <span style="font-style: italic">attributes</span> 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.</p><p>I like to think of Pollen markup a way of capturing not just the text, but also my <span style="font-weight: bold">ideas about the text</span>. 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.</p><p>In so doing, Pollen markup becomes the source code of the book. Let’s try it out.</p><h5>7.3.1<tt> </tt><a name="(part._.Creating_a_.Pollen_markup_file)"></a>Creating a Pollen markup file</h5><p>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 <a href="second-tutorial.html" data-pltdoc="x">Second tutorial</a>, we’ll start with our desired output filename, <span class="stt">article.html</span>, and then append the Pollen markup suffix, <span class="stt">.pm</span>.</p><p>In DrRacket, start a new file called <span class="stt">article.html.pm</span> like so (BTW you can use any sample text you like):</p><div class="fileblock"><div class="SIntrapara"><div class="fileblock_filetitle"><span class="fileblock_filename"><span class="stt">"article.html.pm"</span></span></div></div><div class="SIntrapara"><div class="fileblock_filecontent"><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktMeta">#lang</span><span class="hspace"> </span><span class="RktMeta"></span><a href="index.html" class="RktModLink" data-pltdoc="x"><span class="RktSym">pollen</span></a><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">I</span><span class="hspace"> </span><span class="RktMeta">want</span><span class="hspace"> </span><span class="RktMeta">to</span><span class="hspace"> </span><span class="RktMeta">attend</span><span class="hspace"> </span><span class="RktMeta">RacketCon</span><span class="hspace"> </span><span class="RktMeta">this</span><span class="hspace"> </span><span class="RktMeta">year.</span></td></tr></table></blockquote></div></div></div></div><p>Consistent with usual authoring-mode policy, when you run this file, you’ll get an X-expression that starts with <span class="RktVal">root</span>:</p><blockquote class="SubFlow"><p><span class="RktVal"><span class="stt">'(root "I want to attend RacketCon this year.")</span></span></p></blockquote><p>Remember, even though the first line of the file is <span class="RktMod">#lang</span> <a href="index.html" class="RktModLink" data-pltdoc="x"><span class="RktSym">pollen</span></a> — same as the last tutorial — the new <span class="stt">.pm</span> 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:</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktMeta">#lang</span><span class="hspace"> </span><span class="RktMeta"></span><a href="index.html" class="RktModLink" data-pltdoc="x"><span class="RktSym">pollen</span></a><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">I</span><span class="hspace"> </span><span class="RktMeta">am</span><span class="hspace"> </span><span class="RktMeta">**so**</span><span class="hspace"> </span><span class="RktMeta">excited</span><span class="hspace"> </span><span class="RktMeta">to</span><span class="hspace"> </span><span class="RktMeta">attend</span><span class="hspace"> </span><span class="RktMeta">__RacketCon__</span><span class="hspace"> </span><span class="RktMeta">this</span><span class="hspace"> </span><span class="RktMeta">year.</span></td></tr></table></blockquote><p>The Markdown syntax will be ignored, and pass through to the output:</p><blockquote class="SubFlow"><p><span class="RktVal"><span class="stt">'(root "I am **so** excited to attend __RacketCon__ this year.")</span></span></p></blockquote><p>Restore the non-Markdown source, and let’s continue.</p><h5>7.3.2<tt> </tt><a name="(part._.Tags___tag_functions)"></a>Tags & tag functions</h5><p>Pollen markup uses the same Pollen command syntax that we first saw in <a href="http://docs.racket-lang.org/pollen/first-tutorial.html#%28part._.Adding_commands%29" data-pltdoc="x">Adding commands</a>. Previously, we used this command syntax to invoke functions like <span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define%29%29" class="RktStxLink" data-pltdoc="x">define</a></span> and <span class="RktSym"><a href="Template.html#%28def._%28%28lib._pollen%2Ftemplate..rkt%29._-~3ehtml%29%29" class="RktValLink" data-pltdoc="x"><span class="nobreak">-></span>html</a></span>. Pollen markup is used to invoke a special kind of function called a <span style="font-style: italic">tag function</span>, which is a function that, by default, adds a tag to the text.</p><p>To see how this works, restore your <span class="stt">article.html.pm</span> file to its original state:</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktMeta">#lang</span><span class="hspace"> </span><span class="RktMeta"></span><a href="index.html" class="RktModLink" data-pltdoc="x"><span class="RktSym">pollen</span></a><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">I</span><span class="hspace"> </span><span class="RktMeta">want</span><span class="hspace"> </span><span class="RktMeta">to</span><span class="hspace"> </span><span class="RktMeta">attend</span><span class="hspace"> </span><span class="RktMeta">RacketCon</span><span class="hspace"> </span><span class="RktMeta">this</span><span class="hspace"> </span><span class="RktMeta">year.</span></td></tr></table></blockquote><p>We can add any tag with Pollen markup, but for now, let’s start with an old favorite: <span class="RktVal">em</span>, 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 <span class="RktVal">em</span>, followed by the text in curly braces, like so:</p><div class="fileblock"><div class="SIntrapara"><div class="fileblock_filetitle"><span class="fileblock_filename"><span class="stt">"article.html.pm"</span></span></div></div><div class="SIntrapara"><div class="fileblock_filecontent"><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktMeta">#lang</span><span class="hspace"> </span><span class="RktMeta"></span><a href="index.html" class="RktModLink" data-pltdoc="x"><span class="RktSym">pollen</span></a><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">I</span><span class="hspace"> </span><span class="RktMeta">want</span><span class="hspace"> </span><span class="RktMeta">to</span><span class="hspace"> </span><span class="RktMeta">attend</span><span class="hspace"> </span><span class="RktMeta">◊</span><span class="RktSym">em</span><span class="RktPn">{</span><span class="RktMeta">RacketCon</span><span class="hspace"> </span><span class="RktMeta">this</span><span class="hspace"> </span><span class="RktMeta">year</span><span class="RktPn">}</span><span class="RktMeta">.</span><span class="RktMeta"></span></td></tr></table></blockquote></div></div></div></div><p>Run this file in DrRacket and see the X-expression that results:</p><blockquote class="SubFlow"><p><span class="RktVal"><span class="stt">'(root "I want to attend " (em "RacketCon this year") ".")</span></span></p></blockquote><p>You won’t be surprised to hear that you can nest tags:</p><div class="fileblock"><div class="SIntrapara"><div class="fileblock_filetitle"><span class="fileblock_filename"><span class="stt">"article.html.pm"</span></span></div></div><div class="SIntrapara"><div class="fileblock_filecontent"><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktMeta">#lang</span><span class="hspace"> </span><span class="RktMeta"></span><a href="index.html" class="RktModLink" data-pltdoc="x"><span class="RktSym">pollen</span></a><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">I</span><span class="hspace"> </span><span class="RktMeta">want</span><span class="hspace"> </span><span class="RktMeta">to</span><span class="hspace"> </span><span class="RktMeta">attend</span><span class="hspace"> </span><span class="RktMeta">◊</span><span class="RktSym">em</span><span class="RktPn">{</span><span class="RktMeta">RacketCon</span><span class="hspace"> </span><span class="RktMeta">◊</span><span class="RktSym">strong</span><span class="RktPn">{</span><span class="RktMeta">this</span><span class="RktPn">}</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta">year</span><span class="RktPn">}</span><span class="RktMeta">.</span><span class="RktMeta"></span></td></tr></table></blockquote></div></div></div></div><p>With the expected results:</p><blockquote class="SubFlow"><p><span class="RktVal"><span class="stt">'(root "I want to attend " (em "RacketCon " (strong "this") " year") ".")</span></span></p></blockquote><h5>7.3.3<tt> </tt><a name="(part._.Attributes)"></a>Attributes</h5><p><span style="font-style: italic">Attributes</span> are like tags for tags. Each attribute is a key–value pair where the key is any name, and the value is a string. Anyone who’s seen HTML is familiar with them:</p><blockquote class="SubFlow"><p><span class="RktVal"><span class="stt"><span class="author">Prof. Leonard</span></span></span></p></blockquote><p>Here, <span class="RktVal">class</span> is an attribute for <span class="RktVal">span</span> that has value <span class="RktVal">"author"</span>. And this is what it looks like as an X-expression:</p><blockquote class="SubFlow"><p><span class="RktVal"><span class="stt">'(span ((class "author")) "Prof. Leonard")</span></span></p></blockquote><p>You can add any number of attributes to a tag (first as an X-expression, then as HTML):</p><blockquote class="SubFlow"><p><span class="RktVal"><span class="stt">'(span ((class "author")(id "primary")(living "true")) "Prof. Leonard")</span></span></p></blockquote><blockquote class="SubFlow"><p><span class="RktVal"><span class="stt"><span class="author" id="primary" living="true">Prof. Leonard</span></span></span></p></blockquote><p>In Pollen markup, attributes have the same logic, but a slightly different syntax. In keeping with the tag notation you just saw, the <span class="RktVal">span</span> tag is added in the usual way:</p><div class="fileblock"><div class="SIntrapara"><div class="fileblock_filetitle"><span class="fileblock_filename"><span class="stt">"article.html.pm"</span></span></div></div><div class="SIntrapara"><div class="fileblock_filecontent"><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktMeta">#lang</span><span class="hspace"> </span><span class="RktMeta"></span><a href="index.html" class="RktModLink" data-pltdoc="x"><span class="RktSym">pollen</span></a><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">◊</span><span class="RktSym">span</span><span class="RktPn">{</span><span class="RktMeta">Prof.</span><span class="hspace"> </span><span class="RktMeta">Leonard</span><span class="RktPn">}</span><span class="RktMeta"></span></td></tr></table></blockquote></div></div></div></div><p>Then you have two options for adding attributes. The verbose way corresponds to how the attributes appear in the X-expression:</p><div class="fileblock"><div class="SIntrapara"><div class="fileblock_filetitle"><span class="fileblock_filename"><span class="stt">"article.html.pm"</span></span></div></div><div class="SIntrapara"><div class="fileblock_filecontent"><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktMeta">#lang</span><span class="hspace"> </span><span class="RktMeta"></span><a href="index.html" class="RktModLink" data-pltdoc="x"><span class="RktSym">pollen</span></a><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">◊</span><span class="RktSym">span</span><span class="RktPn">[</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/quote.html#%28form._%28%28quote._~23~25kernel%29._quote%29%29" class="RktStxLink" data-pltdoc="x">'</a></span><span class="RktPn">(</span><span class="RktPn">(</span><span class="RktSym">class</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktVal">"author"</span><span class="RktPn">)</span><span class="RktPn">(</span><span class="RktSym">id</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktVal">"primary"</span><span class="RktPn">)</span><span class="RktPn">(</span><span class="RktSym">living</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktVal">"true"</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">{</span><span class="RktMeta">Prof.</span><span class="hspace"> </span><span class="RktMeta">Leonard</span><span class="RktPn">}</span><span class="RktMeta"></span></td></tr></table></blockquote></div></div></div></div><p>Each key–value pair is in parentheses, and then the list of pairs is within parentheses, with a <span class="RktSym"><a href="http://docs.racket-lang.org/reference/quote.html#%28form._%28%28quote._~23~25kernel%29._quote%29%29" class="RktStxLink" data-pltdoc="x">quote</a></span> (<span class="RktInBG"><span class="hspace"></span><span class="RktIn">'</span><span class="hspace"></span></span>) at the front that signals that the text should be used literally.</p><p>This involves some superfluous typing, however, so Pollen also supports an abbreviated syntax for attributes:</p><div class="fileblock"><div class="SIntrapara"><div class="fileblock_filetitle"><span class="fileblock_filename"><span class="stt">"article.html.pm"</span></span></div></div><div class="SIntrapara"><div class="fileblock_filecontent"><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktMeta">#lang</span><span class="hspace"> </span><span class="RktMeta"></span><a href="index.html" class="RktModLink" data-pltdoc="x"><span class="RktSym">pollen</span></a><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">◊</span><span class="RktSym">span</span><span class="RktPn">[</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/quote.html#%28form._%28%28quote._~23~25kernel%29._quote%29%29" class="RktStxLink" data-pltdoc="x">'</a></span><span class="RktSym">class:</span><span class="RktVal">"author"</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/quote.html#%28form._%28%28quote._~23~25kernel%29._quote%29%29" class="RktStxLink" data-pltdoc="x">'</a></span><span class="RktSym">id:</span><span class="RktVal">"primary"</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/quote.html#%28form._%28%28quote._~23~25kernel%29._quote%29%29" class="RktStxLink" data-pltdoc="x">'</a></span><span class="RktSym">living:</span><span class="RktVal">"true"</span><span class="RktPn">]</span><span class="RktPn">{</span><span class="RktMeta">Prof.</span><span class="hspace"> </span><span class="RktMeta">Leonard</span><span class="RktPn">}</span><span class="RktMeta"></span></td></tr></table></blockquote></div></div></div></div><p>In this form, each attribute key starts with a quote mark <span class="RktInBG"><span class="hspace"></span><span class="RktIn">'</span><span class="hspace"></span></span> and ends with a colon <span class="RktInBG"><span class="hspace"></span><span class="RktIn">:</span><span class="hspace"></span></span>. As before, the attribute value is in quotation marks.</p><p>Both of these forms will produce the same X-expression:</p><blockquote class="SubFlow"><p><span class="RktVal"><span class="stt">'(span ((class "author")(id "primary")(living "true")) "Prof. Leonard")</span></span></p></blockquote><p>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 <a href="http://docs.racket-lang.org/pollen/second-tutorial.html#%28part._.X-expressions%29" data-pltdoc="x">X-expressions</a> are just alternative notation for the standard angle-bracket notation used in HTML. So if you wanted HTML like this:</p><blockquote class="SubFlow"><p><span class="RktVal"><span class="stt"><div class="red" style="font-size:150%">Important <em>News</em></div></span></span></p></blockquote><p>You could write it in Pollen markup like so:</p><blockquote class="SubFlow"><p><span class="RktVal"><span class="stt">◊div['class:"red" style:"font-size:150%"]{Important ◊em{News}}</span></span></p></blockquote><p>And then just convert it (using the <span class="RktSym"><a href="Template.html#%28def._%28%28lib._pollen%2Ftemplate..rkt%29._-~3ehtml%29%29" class="RktValLink" data-pltdoc="x"><span class="nobreak">-></span>html</a></span> 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.</p><p>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.</p><p>In the XML spirit, Pollen markup lets you use any tags you want. That’s considerably less boring.</p><h5>7.3.4<tt> </tt><a name="(part._.What_are_custom_tags_good_for_)"></a>What are custom tags good for?</h5><p>XML jocks can skip this section, since you already know. But if you’ve been mired in Markdown or HTML, read on.</p><p>Tags, broadly speaking, are a means of annotating a text with extra information, which I’ll call <span style="font-style: italic">metadata</span> (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 <span style="font-style: italic">semantic markup</span> and <span style="font-style: italic">format independence</span>.</p><h5>7.3.5<tt> </tt><a name="(part._.Semantic_markup)"></a>Semantic markup</h5><p><span style="font-style: italic">Semantic markup</span> means adding metadata to text according to the meaning of the text, not merely its intended visual appearance. So rather than tagging <span class="RktVal">RacketCon</span> with an <span class="RktVal">em</span> tag, as we did above to indicate how the word should look, maybe we would tag it with an <span class="RktVal">event</span> tag, to indicate what <span style="font-style: italic">kind</span> of thing it is.</p><p>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 <span class="RktVal">em</span>. But in semantic terms, one would tag them <span class="RktVal">movie-title</span>, <span class="RktVal">first-use</span>, <span class="RktVal">heading</span>, as appropriate.</p><p>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 <span class="RktVal">movie-title</span> rather than <span class="RktVal">italic</span>, 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.</p><h5>7.3.6<tt> </tt><a name="(part._.Format_independence)"></a>Format independence</h5><p>The second benefit of custom tags is <span style="font-style: italic">format independence</span>, or the ability to change the rendering of the text to suit a particular device or context.</p><p>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.</p><p>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.</p><blockquote class="refpara"><blockquote class="refcolumn"><blockquote class="refcontent"><p>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.</p></blockquote></blockquote></blockquote><p>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.</p><p>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.</p><blockquote class="refpara"><blockquote class="refcolumn"><blockquote class="refcontent"><p>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.</p></blockquote></blockquote></blockquote><p>For a document to be format independent, two conditions have to be satisfied.</p><p>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 <span class="RktVal">movie-title</span> onto visual tags like <span class="RktVal">em</span>). 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.</p><p>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 <span class="RktVal">h1</span> and <span class="RktVal">span</span>. These have no meaning outside of HTML, and thus will always cause conversion problems. The <a href="http://docs.racket-lang.org/pollen/second-tutorial.html#%28part._.Prelude__my_principled_objection_to_.Markdown%29" data-pltdoc="x">same goes for Markdown</a>, which is simply HTML in disguise.</p><p>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.</p><h5>7.3.7<tt> </tt><a name="(part._.Using_custom_tags)"></a>Using custom tags</h5><p>You can insert a custom tag using the same syntax as any other tag. Suppose you want to use an <span class="RktVal">event</span> tag to mark events. You would insert it like so:</p><div class="fileblock"><div class="SIntrapara"><div class="fileblock_filetitle"><span class="fileblock_filename"><span class="stt">"article.html.pm"</span></span></div></div><div class="SIntrapara"><div class="fileblock_filecontent"><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktMeta">#lang</span><span class="hspace"> </span><span class="RktMeta"></span><a href="index.html" class="RktModLink" data-pltdoc="x"><span class="RktSym">pollen</span></a><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">I</span><span class="hspace"> </span><span class="RktMeta">want</span><span class="hspace"> </span><span class="RktMeta">to</span><span class="hspace"> </span><span class="RktMeta">attend</span><span class="hspace"> </span><span class="RktMeta">◊</span><span class="RktSym">event</span><span class="RktPn">{</span><span class="RktMeta">RacketCon</span><span class="RktPn">}</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta">this</span><span class="hspace"> </span><span class="RktMeta">year.</span></td></tr></table></blockquote></div></div></div></div><p>This markup will turn into this X-expression:</p><blockquote class="SubFlow"><p><span class="RktVal"><span class="stt">'(root "I want to attend " (event "RacketCon") " this year.")</span></span></p></blockquote><p>Which is equivalent to this XML:</p><blockquote class="SubFlow"><p><span class="RktVal"><span class="stt"><root>I want to attend <event>RacketCon</event> this year.</root></span></span></p></blockquote><p>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.</p><p>Don’t take my word for it. See what happens if you write this:</p><div class="fileblock"><div class="SIntrapara"><div class="fileblock_filetitle"><span class="fileblock_filename"><span class="stt">"article.html.pm"</span></span></div></div><div class="SIntrapara"><div class="fileblock_filecontent"><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktMeta">#lang</span><span class="hspace"> </span><span class="RktMeta"></span><a href="index.html" class="RktModLink" data-pltdoc="x"><span class="RktSym">pollen</span></a><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">I</span><span class="hspace"> </span><span class="RktMeta">want</span><span class="hspace"> </span><span class="RktMeta">to</span><span class="hspace"> </span><span class="RktMeta">attend</span><span class="hspace"> </span><span class="RktMeta">◊</span><span class="RktSym">verylongandimpracticaltagname</span><span class="RktPn">{</span><span class="RktMeta">RacketCon</span><span class="RktPn">}</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta">this</span><span class="hspace"> </span><span class="RktMeta">year.</span></td></tr></table></blockquote></div></div></div></div><p>One small but important exception to this rule. If you were wondering why I sometimes call them <span style="font-style: italic">tag functions</span> instead of just <span style="font-style: italic">tags</span>, 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.</p><p>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.</p><p>For instance, let’s suppose you try to use a custom tag called <span class="RktVal">length</span>:</p><div class="fileblock"><div class="SIntrapara"><div class="fileblock_filetitle"><span class="fileblock_filename"><span class="stt">"article.html.pm"</span></span></div></div><div class="SIntrapara"><div class="fileblock_filecontent"><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktMeta">#lang</span><span class="hspace"> </span><span class="RktMeta"></span><a href="index.html" class="RktModLink" data-pltdoc="x"><span class="RktSym">pollen</span></a><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">The</span><span class="hspace"> </span><span class="RktMeta">Panama</span><span class="hspace"> </span><span class="RktMeta">Canal</span><span class="hspace"> </span><span class="RktMeta">is</span><span class="hspace"> </span><span class="RktMeta">◊</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#%28def._%28%28quote._~23~25kernel%29._length%29%29" class="RktValLink" data-pltdoc="x">length</a></span><span class="RktPn">{</span><span class="RktMeta">77km</span><span class="RktPn">}</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta">across.</span></td></tr></table></blockquote></div></div></div></div><p>When you run this file, you get an error:</p><blockquote class="SubFlow"><p><span class="RktErr"><span class="stt">length: contract violation;<br/>expected: list?<br/>  given: "77km"</span></span></p></blockquote><p>The problem is that Racket already provides a function called <span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#%28def._%28%28quote._~23~25kernel%29._length%29%29" class="RktValLink" data-pltdoc="x">length</a></span>. Consistent with the usual rules of Pollen command notation, your command is interpreted as an attempt to invoke the <span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#%28def._%28%28quote._~23~25kernel%29._length%29%29" class="RktValLink" data-pltdoc="x">length</a></span> function, rather than apply a tag named <span class="RktVal">length</span>.</p><p>In practice, namespace clashes are rare. But if necessary, they’re easy to work around (for the simplest method, see <a href="http://docs.racket-lang.org/pollen/reader.html#%28part._.Invoking_tag_functions%29" data-pltdoc="x">Invoking tag functions</a>).</p><h5>7.3.8<tt> </tt><a name="(part._.Choosing_custom_tags)"></a>Choosing custom tags</h5><p>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:</p><ul><li><p><span style="font-weight: bold">You’re never doing it wrong.</span> 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.</p></li><li><p><span style="font-weight: bold">Tag iteratively.</span> 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 …</p></li><li><p><span style="font-weight: bold">Tags emerge from writing.</span> 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.</p></li><li><p><span style="font-weight: bold">The best tag system is the one you’ll stick with.</span> 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.</p></li><li><p><span style="font-weight: bold">For boilerplate, tags are faster than text.</span> 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.</p></li></ul><p>And most important:</p><ul><li><p><span style="font-weight: bold">Tags are functions.</span> As I <a href="third-tutorial.html#%28part._.Tags___tag_functions%29" data-pltdoc="x">mentioned above</a>, 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. </p></li></ul><p>As we’ll see in the next section, this is where your book truly becomes programmable.</p><h4>7.4<tt> </tt><a name="(part._.Tags_are_functions)"></a>Tags are functions</h4><div class="noskip"><blockquote class="refpara"><blockquote class="refcolumn"><blockquote class="refcontent"><p>Don’t skip this section! It explains a concept that’s essential to understanding how Pollen works.</p></blockquote></blockquote></blockquote></div><p>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.</p><p>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.</p><p>I think most of you know what a function is, but just to be safe — in programming, a <span style="font-style: italic">function</span> 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 <span style="font-style: italic">calling</span> the function.</p><p>Leading us to the Three Golden Rules of Pollen Tags:</p><ol><li><p><span style="font-weight: bold">Every Pollen tag calls a function with the same name.</span></p></li><li><p><span style="font-weight: bold">The input values for that function are the attributes and content of the tag.</span></p></li><li><p><span style="font-weight: bold">The whole tag — tag name, attributes, and content — is replaced with the return value of the called function.</span></p></li></ol><p>You’ve already seen the simplest kind of function in a Pollen document: the <a href="third-tutorial.html#%28part._.Tags___tag_functions%29" data-pltdoc="x">default tag function</a>, which emulates the behavior of standard markup tags.</p><p>Let’s revisit an earlier example, now with the help of the Golden Rules:</p><div class="fileblock"><div class="SIntrapara"><div class="fileblock_filetitle"><span class="fileblock_filename"><span class="stt">"article.html.pm"</span></span></div></div><div class="SIntrapara"><div class="fileblock_filecontent"><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktMeta">#lang</span><span class="hspace"> </span><span class="RktMeta"></span><a href="index.html" class="RktModLink" data-pltdoc="x"><span class="RktSym">pollen</span></a><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">I</span><span class="hspace"> </span><span class="RktMeta">want</span><span class="hspace"> </span><span class="RktMeta">to</span><span class="hspace"> </span><span class="RktMeta">attend</span><span class="hspace"> </span><span class="RktMeta">◊</span><span class="RktSym">em</span><span class="RktPn">{</span><span class="RktMeta">RacketCon</span><span class="hspace"> </span><span class="RktMeta">◊</span><span class="RktSym">strong</span><span class="RktPn">{</span><span class="RktMeta">this</span><span class="RktPn">}</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta">year</span><span class="RktPn">}</span><span class="RktMeta">.</span><span class="RktMeta"></span></td></tr></table></blockquote></div></div></div></div><p>What happens when you run this source? Working from the inside out, Pollen calls the function <span class="RktVal">strong</span> with the input <span class="RktVal">"this"</span>. The result is <span class="RktVal">(strong "this")</span>. Then Pollen calls the function <span class="RktVal">em</span> with the three input values <span class="RktVal">"RacketCon " (strong "this") " year"</span>, which yields <span class="RktVal">(em "RacketCon " (strong "this") " year")</span>. Finally, Pollen calls the <span class="RktVal">root</span> function with everything in the document, resulting in:</p><blockquote class="SubFlow"><p><span class="RktVal"><span class="stt">'(root "I want to attend " (em "RacketCon " (strong "this") " year") ".")</span></span></p></blockquote><h5>7.4.1<tt> </tt><a name="(part._.Attaching_behavior_to_tags)"></a>Attaching behavior to tags</h5><p>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:</p><ul><li><p>Automatically detect cross-references and add hyperlinks.</p></li><li><p>Pull in data from an external source.</p></li><li><p>Generate tables, figures, and other fiddly layout objects.</p></li><li><p>Change content based on given conditions.</p></li><li><p>Automatically detect line breaks, paragraphs, and lists.</p></li><li><p>Insert boilerplate text.</p></li><li><p>Anything annoying or repetitive.</p></li><li><p>Mathematical computations.</p></li><li><p>… and anything else you like to do with a programming language.</p></li></ul><blockquote class="refpara"><blockquote class="refcolumn"><blockquote class="refcontent"><p>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.</p></blockquote></blockquote></blockquote><p>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.</p><p>For example, let’s redefine the <span class="RktVal">strong</span> tag in our example above to simply print <span class="RktVal">BOOM</span>:</p><div class="fileblock"><div class="SIntrapara"><div class="fileblock_filetitle"><span class="fileblock_filename"><span class="stt">"article.html.pm"</span></span></div></div><div class="SIntrapara"><div class="fileblock_filecontent"><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktMeta">#lang</span><span class="hspace"> </span><span class="RktMeta"></span><a href="index.html" class="RktModLink" data-pltdoc="x"><span class="RktSym">pollen</span></a><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">◊</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define%29%29" class="RktStxLink" data-pltdoc="x">define</a></span><span class="RktPn">[</span><span class="RktPn">(</span><span class="RktSym">strong</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktMeta">.</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym"><a href="http://docs.racket-lang.org/plot/renderer2d.html#%28def._%28%28lib._plot%2Fmain..rkt%29._lines%29%29" class="RktValLink" data-pltdoc="x">lines</a></span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">{</span><span class="RktMeta">BOOM</span><span class="RktPn">}</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">I</span><span class="hspace"> </span><span class="RktMeta">want</span><span class="hspace"> </span><span class="RktMeta">to</span><span class="hspace"> </span><span class="RktMeta">attend</span><span class="hspace"> </span><span class="RktMeta">◊</span><span class="RktSym">em</span><span class="RktPn">{</span><span class="RktMeta">RacketCon</span><span class="hspace"> </span><span class="RktMeta">◊</span><span class="RktSym">strong</span><span class="RktPn">{</span><span class="RktMeta">this</span><span class="RktPn">}</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta">year</span><span class="RktPn">}</span><span class="RktMeta"></span></td></tr></table></blockquote></div></div></div></div><p>When you run this file, you indeed get:</p><blockquote class="SubFlow"><p><span class="RktVal"><span class="stt">'(root "I want to attend " (em "RacketCon " "BOOM" " year"))</span></span></p></blockquote><p>How does this work? First, although you can define a function in Pollen command syntax using either of <a href="http://docs.racket-lang.org/pollen/reader.html#%28part._.The_two_command_modes__text_mode___.Racket_mode%29" data-pltdoc="x">The two command modes: text mode & Racket mode</a>, 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):</p><div class="fileblock"><div class="SIntrapara"><div class="fileblock_filetitle"><span class="fileblock_filename"><span class="stt">"article.html.pm"</span></span></div></div><div class="SIntrapara"><div class="fileblock_filecontent"><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktMeta">#lang</span><span class="hspace"> </span><span class="RktMeta"></span><a href="index.html" class="RktModLink" data-pltdoc="x"><span class="RktSym">pollen</span></a><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">◊</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define%29%29" class="RktStxLink" data-pltdoc="x">define</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">strong</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">word</span><span class="RktPn">)</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktVal">"BOOM"</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">I</span><span class="hspace"> </span><span class="RktMeta">want</span><span class="hspace"> </span><span class="RktMeta">to</span><span class="hspace"> </span><span class="RktMeta">attend</span><span class="hspace"> </span><span class="RktMeta">◊</span><span class="RktSym">em</span><span class="RktPn">{</span><span class="RktMeta">RacketCon</span><span class="hspace"> </span><span class="RktMeta">◊</span><span class="RktSym">strong</span><span class="RktPn">{</span><span class="RktMeta">this</span><span class="RktPn">}</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta">year</span><span class="RktPn">}</span><span class="RktMeta">.</span><span class="RktMeta"></span></td></tr></table></blockquote></div></div></div></div><p>Let’s look at our new function definition. As usual, we start with the lozenge character (<span class="RktInBG"><span class="hspace"></span><span class="RktIn">◊</span><span class="hspace"></span></span>) to denote a Pollen command. Then we use <span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define%29%29" class="RktStxLink" data-pltdoc="x">define</a></span> to introduce a function definition. The name of the function comes next, which needs to match our tag name, <span class="RktVal">strong</span>. The expression <span class="RktPn">(</span><span class="RktSym">strong</span><span class="stt"> </span><span class="RktSym">word</span><span class="RktPn">)</span> means “the name of this function is <span class="RktSym">strong</span>, and it takes a single word as input, which we’ll refer to as <span class="RktSym">word</span>.” Finally we have the return value, which is <span class="RktVal">"BOOM"</span>.</p><p>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 <span class="RktVal">strong</span> with the input <span class="RktVal">"this"</span> — same as before. But this time, the result of the <span class="RktSym">strong</span> function is not <span class="RktVal">(strong "this")</span>, but simply <span class="RktVal">BOOM</span>. Then Pollen calls the function <span class="RktVal">em</span> with the three input values <span class="RktVal">"RacketCon " "BOOM" " year"</span>, which yields <span class="RktVal">(em "RacketCon " "BOOM" " year")</span>. Finally, Pollen calls the <span class="RktVal">root</span> function with everything in the document, resulting in:</p><blockquote class="SubFlow"><p><span class="RktVal"><span class="stt">'(root "I want to attend " (em "RacketCon " "BOOM" " year"))</span></span></p></blockquote><p>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. <span style="font-weight: bold">If you get this, and the Golden Rules, you get everything.</span></p><h5>7.4.2<tt> </tt><a name="(part._.Notes_for_experienced_programmers)"></a>Notes for experienced programmers</h5><p>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.)</p><h5>7.4.2.1<tt> </tt><a name="(part._.Point_of_no_return)"></a>Point of no <span class="RktSym">return</span><span class="RktMeta"></span></h5><p> If you’ve written functions in other programming languages, you might be accustomed to using a <span class="RktSym">return</span><span class="RktMeta"></span> 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, <span class="RktVal">"BAP"</span> becomes the return value because it’s in the last position, and <span class="RktVal">"BOOM"</span> is ignored:</p><div class="fileblock"><div class="SIntrapara"><div class="fileblock_filetitle"><span class="fileblock_filename"><span class="stt">"article.html.pm"</span></span></div></div><div class="SIntrapara"><div class="fileblock_filecontent"><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktMeta">#lang</span><span class="hspace"> </span><span class="RktMeta"></span><a href="index.html" class="RktModLink" data-pltdoc="x"><span class="RktSym">pollen</span></a><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">◊</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define%29%29" class="RktStxLink" data-pltdoc="x">define</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">strong</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">word</span><span class="RktPn">)</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktVal">"BOOM"</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktVal">"BAP"</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">I</span><span class="hspace"> </span><span class="RktMeta">want</span><span class="hspace"> </span><span class="RktMeta">to</span><span class="hspace"> </span><span class="RktMeta">attend</span><span class="hspace"> </span><span class="RktMeta">◊</span><span class="RktSym">em</span><span class="RktPn">{</span><span class="RktMeta">RacketCon</span><span class="hspace"> </span><span class="RktMeta">◊</span><span class="RktSym">strong</span><span class="RktPn">{</span><span class="RktMeta">this</span><span class="RktPn">}</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta">year</span><span class="RktPn">}</span><span class="RktMeta">.</span><span class="RktMeta"></span></td></tr></table></blockquote></div></div></div></div><h5>7.4.2.2<tt> </tt><a name="(part._.Multiple_input_values___rest_arguments)"></a>Multiple input values & rest arguments</h5><p> 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 <span class="RktSym">em</span> rather than <span class="RktSym">strong</span>:</p><div class="fileblock"><div class="SIntrapara"><div class="fileblock_filetitle"><span class="fileblock_filename"><span class="stt">"article.html.pm"</span></span></div></div><div class="SIntrapara"><div class="fileblock_filecontent"><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktMeta">#lang</span><span class="hspace"> </span><span class="RktMeta"></span><a href="index.html" class="RktModLink" data-pltdoc="x"><span class="RktSym">pollen</span></a><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">◊</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define%29%29" class="RktStxLink" data-pltdoc="x">define</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">em</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">word</span><span class="RktPn">)</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktVal">"BOOM"</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">I</span><span class="hspace"> </span><span class="RktMeta">want</span><span class="hspace"> </span><span class="RktMeta">to</span><span class="hspace"> </span><span class="RktMeta">attend</span><span class="hspace"> </span><span class="RktMeta">◊</span><span class="RktSym">em</span><span class="RktPn">{</span><span class="RktMeta">RacketCon</span><span class="hspace"> </span><span class="RktMeta">◊</span><span class="RktSym">strong</span><span class="RktPn">{</span><span class="RktMeta">this</span><span class="RktPn">}</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta">year</span><span class="RktPn">}</span><span class="RktMeta">.</span><span class="RktMeta"></span></td></tr></table></blockquote></div></div></div></div><p>Look what happens:</p><blockquote class="SubFlow"><p><span class="RktErr"><span class="stt">em: arity mismatch;<br/>the expected number of arguments does not match the given number<br/>expected: 1<br/>  given: 3</span></span></p></blockquote><p>The error arises because the <span class="RktSym">em</span> function is getting three arguments — <span class="RktVal">"RacketCon " "BOOM" " year"</span> — but has been defined to only accept one argument, <span class="RktSym">word</span>. This is the “arity mismatch.”</p><p>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 <span style="font-style: italic"><a href="http://docs.racket-lang.org/guide/contracts-general-functions.html#%28part._contracts-rest-args%29" data-pltdoc="x">rest argument</a></span> (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 <span class="RktInBG"><span class="hspace"></span><span class="RktIn">.</span><span class="hspace"></span></span> before:</p><div class="fileblock"><div class="SIntrapara"><div class="fileblock_filetitle"><span class="fileblock_filename"><span class="stt">"article.html.pm"</span></span></div></div><div class="SIntrapara"><div class="fileblock_filecontent"><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktMeta">#lang</span><span class="hspace"> </span><span class="RktMeta"></span><a href="index.html" class="RktModLink" data-pltdoc="x"><span class="RktSym">pollen</span></a><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">◊</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define%29%29" class="RktStxLink" data-pltdoc="x">define</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">em</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktMeta">.</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">parts</span><span class="RktPn">)</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktVal">"BOOM"</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">I</span><span class="hspace"> </span><span class="RktMeta">want</span><span class="hspace"> </span><span class="RktMeta">to</span><span class="hspace"> </span><span class="RktMeta">attend</span><span class="hspace"> </span><span class="RktMeta">◊</span><span class="RktSym">em</span><span class="RktPn">{</span><span class="RktMeta">RacketCon</span><span class="hspace"> </span><span class="RktMeta">◊</span><span class="RktSym">strong</span><span class="RktPn">{</span><span class="RktMeta">this</span><span class="RktPn">}</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta">year</span><span class="RktPn">}</span><span class="RktMeta">.</span><span class="RktMeta"></span></td></tr></table></blockquote></div></div></div></div><p>This time, the source file will run without an error, producing this:</p><blockquote class="SubFlow"><p><span class="RktVal"><span class="stt">'(root "I want to attend " "BOOM" ".")</span></span></p></blockquote><p>A rest argument like <span class="RktSym">parts</span> is a <span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#%28def._%28%28quote._~23~25kernel%29._list%29%29" class="RktValLink" data-pltdoc="x">list</a></span> of individual arguments. So if you want to unpack & process these arguments separately, you can use Racket’s extensive list-processing functions (see <a href="http://docs.racket-lang.org/guide/pairs.html" data-pltdoc="x">Pairs and Lists</a>). Also see <span class="RktSym"><a href="http://docs.racket-lang.org/reference/quasiquote.html#%28form._%28%28lib._racket%2Fprivate%2Fletstx-scheme..rkt%29._quasiquote%29%29" class="RktStxLink" data-pltdoc="x">quasiquote</a></span> below.</p><h5>7.4.2.3<tt> </tt><a name="(part._.Returning_an_.X-expression)"></a>Returning an X-expression</h5><p> 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:</p><div class="fileblock"><div class="SIntrapara"><div class="fileblock_filetitle"><span class="fileblock_filename"><span class="stt">"article.html.pm"</span></span></div></div><div class="SIntrapara"><div class="fileblock_filecontent"><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktMeta">#lang</span><span class="hspace"> </span><span class="RktMeta"></span><a href="index.html" class="RktModLink" data-pltdoc="x"><span class="RktSym">pollen</span></a><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">◊</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define%29%29" class="RktStxLink" data-pltdoc="x">define</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">em</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktMeta">.</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">parts</span><span class="RktPn">)</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/quote.html#%28form._%28%28quote._~23~25kernel%29._quote%29%29" class="RktStxLink" data-pltdoc="x">'</a></span><span class="RktPn">(</span><span class="RktSym">big</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktVal">"BOOM"</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">I</span><span class="hspace"> </span><span class="RktMeta">want</span><span class="hspace"> </span><span class="RktMeta">to</span><span class="hspace"> </span><span class="RktMeta">attend</span><span class="hspace"> </span><span class="RktMeta">◊</span><span class="RktSym">em</span><span class="RktPn">{</span><span class="RktMeta">RacketCon</span><span class="hspace"> </span><span class="RktMeta">◊</span><span class="RktSym">strong</span><span class="RktPn">{</span><span class="RktMeta">this</span><span class="RktPn">}</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta">year</span><span class="RktPn">}</span><span class="RktMeta">.</span><span class="RktMeta"></span></td></tr></table></blockquote></div></div></div></div><p>Which produces:</p><blockquote class="SubFlow"><p><span class="RktVal"><span class="stt">'(root "I want to attend " (big "BOOM") ".")</span></span></p></blockquote><p>The <span class="RktSym"><a href="http://docs.racket-lang.org/reference/quote.html#%28form._%28%28quote._~23~25kernel%29._quote%29%29" class="RktStxLink" data-pltdoc="x">quote</a></span> mark <span class="RktInBG"><span class="hspace"></span><span class="RktIn">'</span><span class="hspace"></span></span> before the X-expression signals to Racket that you want to use what follows as a literal value.</p><p>To build X-expressions that are more elaborate, you have two options.</p><p>First is <span class="RktSym"><a href="http://docs.racket-lang.org/reference/quasiquote.html#%28form._%28%28lib._racket%2Fprivate%2Fletstx-scheme..rkt%29._quasiquote%29%29" class="RktStxLink" data-pltdoc="x">quasiquote</a></span>. Quasiquote works like quote, but starts with a backtick character <span class="RktInBG"><span class="hspace"></span><span class="RktIn">`</span><span class="hspace"></span></span>. What makes it “quasi” is that you can insert variables using the <span class="RktSym"><a href="http://docs.racket-lang.org/reference/quasiquote.html#%28form._%28%28quote._~23~25kernel%29._unquote%29%29" class="RktStxLink" data-pltdoc="x">unquote</a></span> operator, which is a comma <span class="RktInBG"><span class="hspace"></span><span class="RktIn">,</span><span class="hspace"></span></span> or merge a list of values with the <span class="RktSym"><a href="http://docs.racket-lang.org/reference/quasiquote.html#%28form._%28%28quote._~23~25kernel%29._unquote-splicing%29%29" class="RktStxLink" data-pltdoc="x">unquote-splicing</a></span> operator, which is a comma followed by an @ sign <span class="RktInBG"><span class="hspace"></span><span class="RktIn">,@</span><span class="hspace"></span></span>.</p><p>Let’s adapt the example above to use <span class="RktSym"><a href="http://docs.racket-lang.org/reference/quasiquote.html#%28form._%28%28lib._racket%2Fprivate%2Fletstx-scheme..rkt%29._quasiquote%29%29" class="RktStxLink" data-pltdoc="x">quasiquote</a></span>. Suppose we want to take the <span class="RktSym">parts</span> we get as input and put them inside a <span class="RktSym">big</span> tag. This is easy to notate with <span class="RktSym"><a href="http://docs.racket-lang.org/reference/quasiquote.html#%28form._%28%28lib._racket%2Fprivate%2Fletstx-scheme..rkt%29._quasiquote%29%29" class="RktStxLink" data-pltdoc="x">quasiquote</a></span> and the <span class="RktSym"><a href="http://docs.racket-lang.org/reference/quasiquote.html#%28form._%28%28quote._~23~25kernel%29._unquote-splicing%29%29" class="RktStxLink" data-pltdoc="x">unquote-splicing</a></span> operator, because <span class="RktSym">parts</span> is a list:</p><div class="fileblock"><div class="SIntrapara"><div class="fileblock_filetitle"><span class="fileblock_filename"><span class="stt">"article.html.pm"</span></span></div></div><div class="SIntrapara"><div class="fileblock_filecontent"><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktMeta">#lang</span><span class="hspace"> </span><span class="RktMeta"></span><a href="index.html" class="RktModLink" data-pltdoc="x"><span class="RktSym">pollen</span></a><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">◊</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define%29%29" class="RktStxLink" data-pltdoc="x">define</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">em</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktMeta">.</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">parts</span><span class="RktPn">)</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/quasiquote.html#%28form._%28%28lib._racket%2Fprivate%2Fletstx-scheme..rkt%29._quasiquote%29%29" class="RktStxLink" data-pltdoc="x">`</a></span><span class="RktPn">(</span><span class="RktSym">big</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/quasiquote.html#%28form._%28%28quote._~23~25kernel%29._unquote-splicing%29%29" class="RktStxLink" data-pltdoc="x">,@</a></span><span class="RktSym">parts</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">I</span><span class="hspace"> </span><span class="RktMeta">want</span><span class="hspace"> </span><span class="RktMeta">to</span><span class="hspace"> </span><span class="RktMeta">attend</span><span class="hspace"> </span><span class="RktMeta">◊</span><span class="RktSym">em</span><span class="RktPn">{</span><span class="RktMeta">RacketCon</span><span class="hspace"> </span><span class="RktMeta">◊</span><span class="RktSym">strong</span><span class="RktPn">{</span><span class="RktMeta">this</span><span class="RktPn">}</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta">year</span><span class="RktPn">}</span><span class="RktMeta">.</span><span class="RktMeta"></span></td></tr></table></blockquote></div></div></div></div><p>Which produces this:</p><blockquote class="SubFlow"><p><span class="RktVal"><span class="stt">'(root "I want to attend " (big "RacketCon " (strong "this") " year") ".")</span></span></p></blockquote><p>Of course you can also nest X-expressions in your return value:</p><div class="fileblock"><div class="SIntrapara"><div class="fileblock_filetitle"><span class="fileblock_filename"><span class="stt">"article.html.pm"</span></span></div></div><div class="SIntrapara"><div class="fileblock_filecontent"><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktMeta">#lang</span><span class="hspace"> </span><span class="RktMeta"></span><a href="index.html" class="RktModLink" data-pltdoc="x"><span class="RktSym">pollen</span></a><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">◊</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define%29%29" class="RktStxLink" data-pltdoc="x">define</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">em</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktMeta">.</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">parts</span><span class="RktPn">)</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/quasiquote.html#%28form._%28%28lib._racket%2Fprivate%2Fletstx-scheme..rkt%29._quasiquote%29%29" class="RktStxLink" data-pltdoc="x">`</a></span><span class="RktPn">(</span><span class="RktSym">extra</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">big</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/quasiquote.html#%28form._%28%28quote._~23~25kernel%29._unquote-splicing%29%29" class="RktStxLink" data-pltdoc="x">,@</a></span><span class="RktSym">parts</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">I</span><span class="hspace"> </span><span class="RktMeta">want</span><span class="hspace"> </span><span class="RktMeta">to</span><span class="hspace"> </span><span class="RktMeta">attend</span><span class="hspace"> </span><span class="RktMeta">◊</span><span class="RktSym">em</span><span class="RktPn">{</span><span class="RktMeta">RacketCon</span><span class="hspace"> </span><span class="RktMeta">◊</span><span class="RktSym">strong</span><span class="RktPn">{</span><span class="RktMeta">this</span><span class="RktPn">}</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta">year</span><span class="RktPn">}</span><span class="RktMeta">.</span><span class="RktMeta"></span></td></tr></table></blockquote></div></div></div></div><p>The second option for building X-expressions is to use the <a href="http://docs.racket-lang.org/txexpr/index.html" data-pltdoc="x">txexpr: Tagged X-expressions</a> library that’s included with Pollen (see those docs for more information).</p><h5>7.4.2.4<tt> </tt><a name="(part._.Interpolating_variables_into_strings)"></a>Interpolating variables into strings</h5><p> The usual way is to use the <span class="RktSym"><a href="http://docs.racket-lang.org/reference/Writing.html#%28def._%28%28quote._~23~25kernel%29._format%29%29" class="RktValLink" data-pltdoc="x">format</a></span> function:</p><p><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/Writing.html#%28def._%28%28quote._~23~25kernel%29._format%29%29" class="RktValLink" data-pltdoc="x">format</a></span><span class="stt"> </span><span class="RktVal">"String with variable: ~a"</span><span class="stt"> </span><span class="RktSym">variable-name</span><span class="RktPn">)</span></p><p>See the docs for <span class="RktSym"><a href="http://docs.racket-lang.org/reference/Writing.html#%28def._%28%28quote._~23~25kernel%29._format%29%29" class="RktValLink" data-pltdoc="x">format</a></span> and <span class="RktSym"><a href="http://docs.racket-lang.org/reference/Writing.html#%28def._%28%28quote._~23~25kernel%29._fprintf%29%29" class="RktValLink" data-pltdoc="x">fprintf</a></span> for your options.</p><p>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 <span class="RktSym"><a href="http://docs.racket-lang.org/reference/Writing.html#%28def._%28%28quote._~23~25kernel%29._format%29%29" class="RktValLink" data-pltdoc="x">format</a></span> is essential:</p><p><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><p>Examples:</p></td></tr><tr><td><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="Template.html#%28def._%28%28lib._pollen%2Ftemplate..rkt%29._-~3ehtml%29%29" class="RktValLink" data-pltdoc="x"><span class="nobreak">-></span>html</a></span><span class="hspace"> </span><span class="RktVal">'</span><span class="RktVal">(</span><span class="RktVal">div</span><span class="hspace"> </span><span class="RktVal">"A raw integer indicates a character code: "</span><span class="hspace"> </span><span class="RktVal">42</span><span class="RktVal">)</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">"<div>A raw integer indicates a character code: &#42;</div>"</span></p></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="Template.html#%28def._%28%28lib._pollen%2Ftemplate..rkt%29._-~3ehtml%29%29" class="RktValLink" data-pltdoc="x"><span class="nobreak">-></span>html</a></span><span class="hspace"> </span><span class="RktVal">`</span><span class="RktVal">(</span><span class="RktVal">div</span><span class="hspace"> </span><span class="RktVal">"Use format to make it a string: "</span><span class="hspace"> </span><span class="RktRdr">,</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/Writing.html#%28def._%28%28quote._~23~25kernel%29._format%29%29" class="RktValLink" data-pltdoc="x">format</a></span><span class="hspace"> </span><span class="RktVal">"~a"</span><span class="hspace"> </span><span class="RktVal">42</span><span class="RktPn">)</span><span class="RktVal">)</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">"<div>Use format to make it a string: 42</div>"</span></p></td></tr></table></blockquote></td></tr></table></p><h5>7.4.2.5<tt> </tt><a name="(part._.Parsing_attributes)"></a>Parsing attributes</h5><p>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 <span class="RktSym"><a href="Tag.html#%28def._%28%28lib._pollen%2Ftag..rkt%29._split-attributes%29%29" class="RktValLink" data-pltdoc="x">split-attributes</a></span> function (in the <span class="RktSym">pollen/tag</span> librar) that you can use in custom tag functions to separate the attributes and elements:</p><div class="fileblock"><div class="SIntrapara"><div class="fileblock_filetitle"><span class="fileblock_filename"><span class="stt">"article.html.pm"</span></span></div></div><div class="SIntrapara"><div class="fileblock_filecontent"><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktMeta">#lang</span><span class="hspace"> </span><span class="RktMeta"></span><a href="index.html" class="RktModLink" data-pltdoc="x"><span class="RktSym">pollen</span></a><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">◊</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/require.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._require%29%29" class="RktStxLink" data-pltdoc="x">require</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">pollen/tag</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">◊</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define%29%29" class="RktStxLink" data-pltdoc="x">define</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">em</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktMeta">.</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">parts</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28quote._~23~25kernel%29._define-values%29%29" class="RktStxLink" data-pltdoc="x">define-values</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">attributes</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">elements</span><span class="RktPn">)</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym"><a href="Tag.html#%28def._%28%28lib._pollen%2Ftag..rkt%29._split-attributes%29%29" class="RktValLink" data-pltdoc="x">split-attributes</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">parts</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/quasiquote.html#%28form._%28%28lib._racket%2Fprivate%2Fletstx-scheme..rkt%29._quasiquote%29%29" class="RktStxLink" data-pltdoc="x">`</a></span><span class="RktPn">(</span><span class="RktSym">extra</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/quasiquote.html#%28form._%28%28quote._~23~25kernel%29._unquote%29%29" class="RktStxLink" data-pltdoc="x">,</a></span><span class="RktSym">attributes</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">big</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/quasiquote.html#%28form._%28%28quote._~23~25kernel%29._unquote-splicing%29%29" class="RktStxLink" data-pltdoc="x">,@</a></span><span class="RktSym">elements</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">I</span><span class="hspace"> </span><span class="RktMeta">want</span><span class="hspace"> </span><span class="RktMeta">to</span><span class="hspace"> </span><span class="RktMeta">attend</span><span class="hspace"> </span><span class="RktMeta">◊</span><span class="RktSym">em</span><span class="RktPn">[</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/quote.html#%28form._%28%28quote._~23~25kernel%29._quote%29%29" class="RktStxLink" data-pltdoc="x">'</a></span><span class="RktSym">key:</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktVal">"value"</span><span class="RktPn">]</span><span class="RktPn">{</span><span class="RktMeta">RacketCon</span><span class="RktPn">}</span><span class="RktMeta">.</span><span class="RktMeta"></span></td></tr></table></blockquote></div></div></div></div><p>This will move the <span class="RktSym">elements</span> inside the <span class="RktSym">big</span> tag, and attach the <span class="RktSym">attributes</span> to the <span class="RktSym">extra</span> tag:</p><blockquote class="SubFlow"><p><span class="RktVal"><span class="stt">'(root "I want to attend " (extra ((key "value")) (big "RacketCon")) ".")</span></span></p></blockquote><h4>7.5<tt> </tt><a name="(part._tutorial-3._.Intermission)"></a>Intermission</h4><p>That was a lot of heavy material. But it also covered the most essential idea in Pollen: that <span style="font-weight: bold">every tag is a function</span>. Congratulations on making it this far.</p><p>The good news is that the rest of this tutorial will feel more relaxed, as we put these new principles to work.</p><p>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 <a href="http://www.buzzfeed.com/search?q=puppies">bail out</a>.</p><p>Otherwise, get ready to rock.</p><h4>7.6<tt> </tt><a name="(part._.Organizing_functions)"></a>Organizing functions</h4><p>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.</p><p>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.</p><blockquote class="refpara"><blockquote class="refcolumn"><blockquote class="refcontent"><p>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.</p></blockquote></blockquote></blockquote><h5>7.6.1<tt> </tt><a name="(part._.Using_.Racket_s_function_libraries)"></a>Using Racket’s function libraries</h5><p>Any function in Racket’s extensive libraries can be called by loading the library with the <span class="RktSym"><a href="http://docs.racket-lang.org/reference/require.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._require%29%29" class="RktStxLink" data-pltdoc="x">require</a></span> command, which will make all its functions and constants available with the usual Pollen command syntax:</p><div class="fileblock"><div class="SIntrapara"><div class="fileblock_filetitle"><span class="fileblock_filename"><span class="stt">"article.html.pm"</span></span></div></div><div class="SIntrapara"><div class="fileblock_filecontent"><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktMeta">#lang</span><span class="hspace"> </span><span class="RktMeta"></span><a href="index.html" class="RktModLink" data-pltdoc="x"><span class="RktSym">pollen</span></a><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">◊</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/require.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._require%29%29" class="RktStxLink" data-pltdoc="x">require</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">racket/math</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">Pi</span><span class="hspace"> </span><span class="RktMeta">is</span><span class="hspace"> </span><span class="RktMeta">close</span><span class="hspace"> </span><span class="RktMeta">to</span><span class="hspace"> </span><span class="RktMeta">◊|</span><span class="RktSym">pi</span><span class="RktMeta">|.</span></td></tr><tr><td><span class="RktMeta">The</span><span class="hspace"> </span><span class="RktMeta">hyperbolic</span><span class="hspace"> </span><span class="RktMeta">sine</span><span class="hspace"> </span><span class="RktMeta">of</span><span class="hspace"> </span><span class="RktMeta">pi</span><span class="hspace"> </span><span class="RktMeta">is</span><span class="hspace"> </span><span class="RktMeta">close</span><span class="hspace"> </span><span class="RktMeta">to</span><span class="hspace"> </span><span class="RktMeta">◊</span><span class="RktPn">(</span><span class="RktSym">sinh</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">pi</span><span class="RktPn">)</span><span class="RktMeta">.</span><span class="RktMeta"></span></td></tr></table></blockquote></div></div></div></div><p>The result:</p><blockquote class="SubFlow"><p><span class="RktVal"><span class="stt">'(root "Pi is close to " 3.141592653589793 "." "\n" "The hyperbolic sine of pi is close to " 11.548739357257748 ".")</span></span></p></blockquote><p>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. <span class="refelem"><span class="refcolumn"><span class="refcontent">This is similar to the restriction introduced in the <a href="http://docs.racket-lang.org/pollen/first-tutorial.html#%28part._.Setting_up_a_preprocessor_source_file%29" data-pltdoc="x">first tutorial</a> where functions used in preprocessor files had to produce text.</span></span></span>
|
|
Pollen won’t stop you from calling a function that returns an incompatible value, like <span class="RktSym"><a href="http://docs.racket-lang.org/plot/plotting.html#%28def._%28%28lib._plot%2Fmain..rkt%29._plot%29%29" class="RktValLink" data-pltdoc="x">plot</a></span>, which returns a bitmap image:</p><div class="fileblock"><div class="SIntrapara"><div class="fileblock_filetitle"><span class="fileblock_filename"><span class="stt">"article.html.pm"</span></span></div></div><div class="SIntrapara"><div class="fileblock_filecontent"><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktMeta">#lang</span><span class="hspace"> </span><span class="RktMeta"></span><a href="index.html" class="RktModLink" data-pltdoc="x"><span class="RktSym">pollen</span></a><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">◊</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/require.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._require%29%29" class="RktStxLink" data-pltdoc="x">require</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">math</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym"><a href="http://docs.racket-lang.org/plot/plotting.html#%28def._%28%28lib._plot%2Fmain..rkt%29._plot%29%29" class="RktValLink" data-pltdoc="x">plot</a></span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">Here</span><span class="RktVal">'</span><span class="RktMeta">s</span><span class="hspace"> </span><span class="RktMeta">a</span><span class="hspace"> </span><span class="RktMeta">sine</span><span class="hspace"> </span><span class="RktMeta">wave:</span></td></tr><tr><td><span class="RktMeta">◊</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/plot/plotting.html#%28def._%28%28lib._plot%2Fmain..rkt%29._plot%29%29" class="RktValLink" data-pltdoc="x">plot</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/plot/renderer2d.html#%28def._%28%28lib._plot%2Fmain..rkt%29._function%29%29" class="RktValLink" data-pltdoc="x">function</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/generic-numbers.html#%28def._%28%28quote._~23~25kernel%29._sin%29%29" class="RktValLink" data-pltdoc="x">sin</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/generic-numbers.html#%28def._%28%28quote._~23~25kernel%29._-%29%29" class="RktValLink" data-pltdoc="x"><span class="nobreak">-</span></a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">pi</span><span class="RktPn">)</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">pi</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">#:label</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktVal">"y</span><span class="hspace"> </span><span class="RktVal">=</span><span class="hspace"> </span><span class="RktVal">sin(x)"</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr></table></blockquote></div></div></div></div><p>But it won’t work when you try to run it in DrRacket or load it in the project server.</p><p>It would be fine, however, to call a different kind of <span class="RktSym"><a href="http://docs.racket-lang.org/plot/plotting.html#%28def._%28%28lib._plot%2Fmain..rkt%29._plot%29%29" class="RktValLink" data-pltdoc="x">plot</a></span> function that returned an SVG result, because any XML-ish data structure can be converted to an X-expression.</p><blockquote class="refpara"><blockquote class="refcolumn"><blockquote class="refcontent"><p>Super web nerds also know that binary data can be converted into XML-ish form by encoding the file as a base64 data URL — but if you know what I’m talking about, then you don’t need my help to try it.</p></blockquote></blockquote></blockquote><p>For functions that don’t return a string or an X-expression, you can always make a conversion by hand. For instance, consider <span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#%28def._%28%28lib._racket%2Flist..rkt%29._range%29%29" class="RktValLink" data-pltdoc="x">range</a></span>, a Racket function that returns a list of integers:</p><div class="fileblock"><div class="SIntrapara"><div class="fileblock_filetitle"><span class="fileblock_filename"><span class="stt">"article.html.pm"</span></span></div></div><div class="SIntrapara"><div class="fileblock_filecontent"><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktMeta">#lang</span><span class="hspace"> </span><span class="RktMeta"></span><a href="index.html" class="RktModLink" data-pltdoc="x"><span class="RktSym">pollen</span></a><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">◊</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/require.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._require%29%29" class="RktStxLink" data-pltdoc="x">require</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">racket/list</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta">A</span><span class="hspace"> </span><span class="RktMeta">list</span><span class="hspace"> </span><span class="RktMeta">of</span><span class="hspace"> </span><span class="RktMeta">integers:</span><span class="hspace"> </span><span class="RktMeta">◊</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#%28def._%28%28lib._racket%2Flist..rkt%29._range%29%29" class="RktValLink" data-pltdoc="x">range</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktVal">5</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr></table></blockquote></div></div></div></div><p>This will produce an error in DrRacket:</p><blockquote class="SubFlow"><p><span class="RktErr"><span class="stt">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)</span></span></p></blockquote><p>In a case like this, you can explicitly convert the return value to a string (in whatever way makes sense):</p><div class="fileblock"><div class="SIntrapara"><div class="fileblock_filetitle"><span class="fileblock_filename"><span class="stt">"article.html.pm"</span></span></div></div><div class="SIntrapara"><div class="fileblock_filecontent"><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktMeta">#lang</span><span class="hspace"> </span><span class="RktMeta"></span><a href="index.html" class="RktModLink" data-pltdoc="x"><span class="RktSym">pollen</span></a><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">◊</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/require.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._require%29%29" class="RktStxLink" data-pltdoc="x">require</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">racket/list</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">racket/string</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta">A</span><span class="hspace"> </span><span class="RktMeta">list</span><span class="hspace"> </span><span class="RktMeta">of</span><span class="hspace"> </span><span class="RktMeta">integers:</span><span class="hspace"> </span><span class="RktMeta">◊</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/strings.html#%28def._%28%28lib._racket%2Fstring..rkt%29._string-join%29%29" class="RktValLink" data-pltdoc="x">string-join</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#%28def._%28%28lib._racket%2Fprivate%2Fmap..rkt%29._map%29%29" class="RktValLink" data-pltdoc="x">map</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/generic-numbers.html#%28def._%28%28quote._~23~25kernel%29._number-~3estring%29%29" class="RktValLink" data-pltdoc="x">number->string</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#%28def._%28%28lib._racket%2Flist..rkt%29._range%29%29" class="RktValLink" data-pltdoc="x">range</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktVal">5</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr></table></blockquote></div></div></div></div><p>And get this output:</p><blockquote class="SubFlow"><p><span class="RktVal"><span class="stt">'(root "A list of integers: " "0 1 2 3 4")</span></span></p></blockquote><h5>7.6.2<tt> </tt><a name="(part._tutorial-3._.Using_the_directory-require_rkt_file)"></a>Using the <span class="stt">directory-require.rkt</span> file</h5><div class="noskip"><blockquote class="refpara"><blockquote class="refcolumn"><blockquote class="refcontent"><p>Don’t skip this section! It explains a concept that’s essential to understanding how Pollen works.</p></blockquote></blockquote></blockquote></div><p>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 <span class="stt">directory-require.rkt</span> file is a special file that is automatically imported by Pollen source files in the same directory. So every function and value provided by <span class="stt">directory-require.rkt</span> can be used in these Pollen files.</p><p>First, using this file is not mandatory. You can always import functions and values from another file using <span class="RktSym"><a href="http://docs.racket-lang.org/reference/require.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._require%29%29" class="RktStxLink" data-pltdoc="x">require</a></span> (as seen in the previous section). The <span class="stt">directory-require.rkt</span> 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.</p><p>Second, notice from the <span class="stt">.rkt</span> suffix that <span class="stt">directory-require.rkt</span> 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 <span class="RktSym"><a href="World.html#%28def._%28%28lib._pollen%2Fworld..rkt%29._world~3adirectory-require%29%29" class="RktValLink" data-pltdoc="x">world:directory-require</a></span> value.</p><p>Third, notice from the <span class="stt">directory-</span> prefix that <span class="stt">directory-require.rkt</span> is only used by Pollen source files <span style="font-style: italic">in the same directory</span>. So if your project has source files nested inside a subdirectory, you’ll need to explicitly create another <span class="stt">directory-require.rkt</span> there and share the functions & values as needed.</p><blockquote class="refpara"><blockquote class="refcolumn"><blockquote class="refcontent"><p>“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.</p></blockquote></blockquote></blockquote><p>Let’s see how this works in practice. In the same directory as <span class="stt">article.html.pm</span>, create a new <span class="stt">directory-require.rkt</span> file as follows:</p><div class="fileblock"><div class="SIntrapara"><div class="fileblock_filetitle"><span class="fileblock_filename"><span class="stt">"directory-require.rkt"</span></span></div></div><div class="SIntrapara"><div class="fileblock_filecontent"><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktMeta">#lang</span><span class="hspace"> </span><span class="RktMeta"></span><a href="http://docs.racket-lang.org/reference/index.html" class="RktModLink" data-pltdoc="x"><span class="RktSym">racket</span></a><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define%29%29" class="RktStxLink" data-pltdoc="x">define</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">author</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktVal">"Trevor</span><span class="hspace"> </span><span class="RktVal">Goodchild"</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/require.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._provide%29%29" class="RktStxLink" data-pltdoc="x">provide</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">author</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr></table></blockquote></div></div></div></div><p>Here we use the <span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define%29%29" class="RktStxLink" data-pltdoc="x">define</a></span> function (which we’ve seen before) to set <span class="RktSym">author</span> equal to <span class="RktVal">"Trevor Goodchild"</span>. Note the final step: consistent with standard Racket rules, we have to explicitly <span class="RktSym"><a href="http://docs.racket-lang.org/reference/require.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._provide%29%29" class="RktStxLink" data-pltdoc="x">provide</a></span> the new value so that other files can see it (unlike Python, things you <span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define%29%29" class="RktStxLink" data-pltdoc="x">define</a></span> in Racket are private by default, not public).</p><p>Then update good old <span class="stt">article.html.pm</span>:</p><div class="fileblock"><div class="SIntrapara"><div class="fileblock_filetitle"><span class="fileblock_filename"><span class="stt">"article.html.pm"</span></span></div></div><div class="SIntrapara"><div class="fileblock_filecontent"><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktMeta">#lang</span><span class="hspace"> </span><span class="RktMeta"></span><a href="index.html" class="RktModLink" data-pltdoc="x"><span class="RktSym">pollen</span></a><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">The</span><span class="hspace"> </span><span class="RktMeta">author</span><span class="hspace"> </span><span class="RktMeta">is</span><span class="hspace"> </span><span class="RktMeta">◊|</span><span class="RktSym">author</span><span class="RktMeta">|.</span></td></tr></table></blockquote></div></div></div></div><p>Run this in DrRacket and you’ll get:</p><blockquote class="SubFlow"><p><span class="RktVal"><span class="stt">'(root "The author is " "Trevor Goodchild" ".")</span></span></p></blockquote><p>Now, in the same dirctory, create a second Pollen source file:</p><div class="fileblock"><div class="SIntrapara"><div class="fileblock_filetitle"><span class="fileblock_filename"><span class="stt">"barticle.html.pm"</span></span></div></div><div class="SIntrapara"><div class="fileblock_filecontent"><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktMeta">#lang</span><span class="hspace"> </span><span class="RktMeta"></span><a href="index.html" class="RktModLink" data-pltdoc="x"><span class="RktSym">pollen</span></a><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">The</span><span class="hspace"> </span><span class="RktMeta">author</span><span class="hspace"> </span><span class="RktMeta">is</span><span class="hspace"> </span><span class="RktMeta">really</span><span class="hspace"> </span><span class="RktMeta">◊|</span><span class="RktSym">author</span><span class="RktMeta">|?</span></td></tr></table></blockquote></div></div></div></div><p>Run this, and you’ll get:</p><blockquote class="SubFlow"><p><span class="RktVal"><span class="stt">'(root "The author is really " "Trevor Goodchild" "?")</span></span></p></blockquote><p>That’s all there is to it. Everything provided by <span class="stt">directory-require.rkt</span> is automatically available within each Pollen source file.</p><p>You can include functions, including tag functions, the same way. For instance, add a function for <span class="RktSym">em</span>:</p><div class="fileblock"><div class="SIntrapara"><div class="fileblock_filetitle"><span class="fileblock_filename"><span class="stt">"directory-require.rkt"</span></span></div></div><div class="SIntrapara"><div class="fileblock_filecontent"><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktMeta">#lang</span><span class="hspace"> </span><span class="RktMeta"></span><a href="http://docs.racket-lang.org/reference/index.html" class="RktModLink" data-pltdoc="x"><span class="RktSym">racket</span></a><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define%29%29" class="RktStxLink" data-pltdoc="x">define</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">author</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktVal">"Trevor</span><span class="hspace"> </span><span class="RktVal">Goodchild"</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define%29%29" class="RktStxLink" data-pltdoc="x">define</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">em</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktMeta">.</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">parts</span><span class="RktPn">)</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/quasiquote.html#%28form._%28%28lib._racket%2Fprivate%2Fletstx-scheme..rkt%29._quasiquote%29%29" class="RktStxLink" data-pltdoc="x">`</a></span><span class="RktPn">(</span><span class="RktSym">extra</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">big</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/quasiquote.html#%28form._%28%28quote._~23~25kernel%29._unquote-splicing%29%29" class="RktStxLink" data-pltdoc="x">,@</a></span><span class="RktSym">parts</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/require.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._provide%29%29" class="RktStxLink" data-pltdoc="x">provide</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">author</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">em</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr></table></blockquote></div></div></div></div><p>Then use it in a source file:</p><div class="fileblock"><div class="SIntrapara"><div class="fileblock_filetitle"><span class="fileblock_filename"><span class="stt">"article.html.pm"</span></span></div></div><div class="SIntrapara"><div class="fileblock_filecontent"><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktMeta">#lang</span><span class="hspace"> </span><span class="RktMeta"></span><a href="index.html" class="RktModLink" data-pltdoc="x"><span class="RktSym">pollen</span></a><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">The</span><span class="hspace"> </span><span class="RktMeta">◊</span><span class="RktSym">em</span><span class="RktPn">{</span><span class="RktMeta">author</span><span class="RktPn">}</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta">is</span><span class="hspace"> </span><span class="RktMeta">◊</span><span class="RktSym">em</span><span class="RktPn">{</span><span class="RktMeta">◊|</span><span class="RktSym">author</span><span class="RktMeta">|</span><span class="RktPn">}</span><span class="RktMeta">.</span><span class="RktMeta"></span></td></tr></table></blockquote></div></div></div></div><p>With the expected results:</p><blockquote class="SubFlow"><p><span class="RktVal"><span class="stt">'(root "The " (extra (big "author")) " is " (extra (big "Trevor Goodchild")) ".")</span></span></p></blockquote><h4>7.7<tt> </tt><a name="(part._.Decoding_markup_via_the_root_tag)"></a>Decoding markup via the <span class="stt">root</span> tag</h4><p>As you’ve seen, the X-expression you get when you run a Pollen markup file always starts with a node called <span class="stt">root</span>. You can attach a tag function to <span class="stt">root</span> the same way as any other tag. For instance, you could do something simple, like change the name of the output X-expression:</p><div class="fileblock"><div class="SIntrapara"><div class="fileblock_filetitle"><span class="fileblock_filename"><span class="stt">"article.html.pm"</span></span></div></div><div class="SIntrapara"><div class="fileblock_filecontent"><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktMeta">#lang</span><span class="hspace"> </span><span class="RktMeta"></span><a href="index.html" class="RktModLink" data-pltdoc="x"><span class="RktSym">pollen</span></a><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">◊</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define%29%29" class="RktStxLink" data-pltdoc="x">define</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">root</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktMeta">.</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">elements</span><span class="RktPn">)</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/quasiquote.html#%28form._%28%28lib._racket%2Fprivate%2Fletstx-scheme..rkt%29._quasiquote%29%29" class="RktStxLink" data-pltdoc="x">`</a></span><span class="RktPn">(</span><span class="RktSym">content</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/quasiquote.html#%28form._%28%28quote._~23~25kernel%29._unquote-splicing%29%29" class="RktStxLink" data-pltdoc="x">,@</a></span><span class="RktSym">elements</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">The</span><span class="hspace"> </span><span class="RktMeta">◊</span><span class="RktSym">tt</span><span class="RktPn">{</span><span class="RktMeta">root</span><span class="RktPn">}</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta">tag</span><span class="hspace"> </span><span class="RktMeta">is</span><span class="hspace"> </span><span class="RktMeta">now</span><span class="hspace"> </span><span class="RktMeta">called</span><span class="hspace"> </span><span class="RktMeta">◊</span><span class="RktSym">tt</span><span class="RktPn">{</span><span class="RktMeta">content</span><span class="RktPn">}</span><span class="RktMeta">.</span><span class="RktMeta"></span></td></tr></table></blockquote></div></div></div></div><p>Resulting in:</p><blockquote class="SubFlow"><p><span class="RktVal"><span class="stt">'(content "The " (tt "root") " tag is now called " (tt "content") ".")</span></span></p></blockquote><p>But unlike other tags in your document, <span class="stt">root</span> contains the entire content of the document. So the function you attach to <span class="stt">root</span> can operate on everything.</p><p>For that reason, one of the most useful things you can do with a tag function attached to <span class="stt">root</span> is <span style="font-style: italic">decoding</span> the content of the page. Decoding refers to any post-processing of content that happens after the tags within the page have been evaluated.</p><p>Decoding is a good way to automatically accomplish:</p><ul><li><p>Detection of linebreaks, paragraphs, and list items based on whitespace.</p></li><li><p>Hyphenation.</p></li><li><p>Typographic optimizations, like smart quotes, dashes, and ligatures.</p></li><li><p>Gathering data for indexing or cross-referencing.</p></li><li><p>Any document enhancements a) that can be handled programmatically and b) that you’d prefer not to hard-code within your source files.</p></li></ul><p>As an example, let’s take one of my favorites — linebreak and paragraph detection. In XML authoring, you have to insert every <span class="stt"><br /></span> and <span class="stt"><p></span> tag by hand. This is profoundly dull, clutters up the source file, and makes editing a chore.</p><p>Instead, let’s make a decoder that allows us to denote a linebreak with a single newline in the source, and a paragraph break with a double newline. Here’s some sample content with single and double newlines:</p><div class="fileblock"><div class="SIntrapara"><div class="fileblock_filetitle"><span class="fileblock_filename"><span class="stt">"article.html.pm"</span></span></div></div><div class="SIntrapara"><div class="fileblock_filecontent"><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktMeta">#lang</span><span class="hspace"> </span><span class="RktMeta"></span><a href="index.html" class="RktModLink" data-pltdoc="x"><span class="RktSym">pollen</span></a><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">The</span><span class="hspace"> </span><span class="RktMeta">first</span><span class="hspace"> </span><span class="RktMeta">line</span><span class="hspace"> </span><span class="RktMeta">of</span><span class="hspace"> </span><span class="RktMeta">the</span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktVal">'</span><span class="RktMeta">first</span><span class="RktVal">'</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta">paragraph.</span></td></tr><tr><td><span class="RktMeta">And</span><span class="hspace"> </span><span class="RktMeta">a</span><span class="hspace"> </span><span class="RktMeta">new</span><span class="hspace"> </span><span class="RktMeta">line.</span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">The</span><span class="hspace"> </span><span class="RktMeta">second</span><span class="hspace"> </span><span class="RktMeta">paragraph</span><span class="hspace"> </span><span class="RktMeta">---</span><span class="hspace"> </span><span class="RktMeta">isn</span><span class="RktVal">'</span><span class="RktMeta">t</span><span class="hspace"> </span><span class="RktMeta">it</span><span class="hspace"> </span><span class="RktMeta">great.</span></td></tr></table></blockquote></div></div></div></div><p>But without a decoder, the newlines just get passed through:</p><blockquote class="SubFlow"><p><span class="RktVal"><span class="stt">'(root "The first line of the 'first' paragraph." "\n" "And a new line." "\n" "\n" "The second paragraph --- isn't it great.")</span></span></p></blockquote><p>When this X-expression is converted to HTML, the newlines persist:</p><blockquote class="SubFlow"><p><span class="RktVal"><span class="stt"><root>The first line of the 'first' paragraph.\nAnd a new line.\n\nThe second paragraph --- isn't it great.</root></span></span></p></blockquote><p>But in HTML, raw newlines are displayed as a single space. So if you view this file in the project server, you’ll see:</p><div class="browser"><div class="SIntrapara">The first line of the 'first' paragraph. And a new line. The second paragraph --- isn't it great.</div></div><p>Not what we want.</p><p>So we need to make a decoder. To do this, we use the <span class="RktSym"><a href="Decode.html#%28def._%28%28lib._pollen%2Fdecode..rkt%29._decode-elements%29%29" class="RktValLink" data-pltdoc="x">decode-elements</a></span> function, which provides hooks to selectively process certain categories of content within the document.</p><blockquote class="refpara"><blockquote class="refcolumn"><blockquote class="refcontent"><p><span class="RktSym"><a href="Decode.html#%28def._%28%28lib._pollen%2Fdecode..rkt%29._decode-elements%29%29" class="RktValLink" data-pltdoc="x">decode-elements</a></span> is a convenience variant of <span class="RktSym"><a href="Decode.html#%28def._%28%28lib._pollen%2Fdecode..rkt%29._decode%29%29" class="RktValLink" data-pltdoc="x">decode</a></span>, which takes a full X-expression as input. Under the hood, they work the same way, so use whichever you prefer.</p></blockquote></blockquote></blockquote><p>Add a basic <span class="RktSym"><a href="Decode.html#%28def._%28%28lib._pollen%2Fdecode..rkt%29._decode-elements%29%29" class="RktValLink" data-pltdoc="x">decode-elements</a></span> to the source file like so:</p><div class="fileblock"><div class="SIntrapara"><div class="fileblock_filetitle"><span class="fileblock_filename"><span class="stt">"article.html.pm"</span></span></div></div><div class="SIntrapara"><div class="fileblock_filecontent"><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktMeta">#lang</span><span class="hspace"> </span><span class="RktMeta"></span><a href="index.html" class="RktModLink" data-pltdoc="x"><span class="RktSym">pollen</span></a><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">◊</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/require.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._require%29%29" class="RktStxLink" data-pltdoc="x">require</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">pollen/decode</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">txexpr</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta">◊</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define%29%29" class="RktStxLink" data-pltdoc="x">define</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">root</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktMeta">.</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">elements</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/txexpr/index.html#%28def._%28%28lib._txexpr%2Fmain..rkt%29._make-txexpr%29%29" class="RktValLink" data-pltdoc="x">make-txexpr</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/quote.html#%28form._%28%28quote._~23~25kernel%29._quote%29%29" class="RktStxLink" data-pltdoc="x">'</a></span><span class="RktSym">root</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#%28def._%28%28quote._~23~25kernel%29._null%29%29" class="RktValLink" data-pltdoc="x">null</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym"><a href="Decode.html#%28def._%28%28lib._pollen%2Fdecode..rkt%29._decode-elements%29%29" class="RktValLink" data-pltdoc="x">decode-elements</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">elements</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">The</span><span class="hspace"> </span><span class="RktMeta">first</span><span class="hspace"> </span><span class="RktMeta">line</span><span class="hspace"> </span><span class="RktMeta">of</span><span class="hspace"> </span><span class="RktMeta">the</span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktVal">'</span><span class="RktMeta">first</span><span class="RktVal">'</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta">paragraph.</span></td></tr><tr><td><span class="RktMeta">And</span><span class="hspace"> </span><span class="RktMeta">a</span><span class="hspace"> </span><span class="RktMeta">new</span><span class="hspace"> </span><span class="RktMeta">line.</span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">The</span><span class="hspace"> </span><span class="RktMeta">second</span><span class="hspace"> </span><span class="RktMeta">paragraph</span><span class="hspace"> </span><span class="RktMeta">---</span><span class="hspace"> </span><span class="RktMeta">isn</span><span class="RktVal">'</span><span class="RktMeta">t</span><span class="hspace"> </span><span class="RktMeta">it</span><span class="hspace"> </span><span class="RktMeta">great.</span></td></tr></table></blockquote></div></div></div></div><p>The <span class="RktSym"><a href="http://docs.racket-lang.org/txexpr/index.html#%28def._%28%28lib._txexpr%2Fmain..rkt%29._make-txexpr%29%29" class="RktValLink" data-pltdoc="x">make-txexpr</a></span> function is a utility from the <span class="RktSym">txexpr</span> package, which is installed with Pollen. It builds a new X-expression from a tag, attribute list, and list of elements. Here, we’ll keep the tag name <span class="stt">root</span>, leave the attributes as <span class="stt">null</span>, and append our decoded list of elements.</p><blockquote class="refpara"><blockquote class="refcolumn"><blockquote class="refcontent"><p>Racket jocks: you could also write this using <span class="RktSym"><a href="http://docs.racket-lang.org/reference/quasiquote.html#%28form._%28%28lib._racket%2Fprivate%2Fletstx-scheme..rkt%29._quasiquote%29%29" class="RktStxLink" data-pltdoc="x">quasiquote</a></span> and <span class="RktSym"><a href="http://docs.racket-lang.org/reference/quasiquote.html#%28form._%28%28quote._~23~25kernel%29._unquote-splicing%29%29" class="RktStxLink" data-pltdoc="x">unquote-splicing</a></span> syntax as <span class="RktSym"><a href="http://docs.racket-lang.org/reference/quasiquote.html#%28form._%28%28lib._racket%2Fprivate%2Fletstx-scheme..rkt%29._quasiquote%29%29" class="RktStxLink" data-pltdoc="x">`</a></span><span class="RktPn">(</span><span class="RktSym">root</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/quasiquote.html#%28form._%28%28quote._~23~25kernel%29._unquote-splicing%29%29" class="RktStxLink" data-pltdoc="x">,@</a></span><span class="RktPn">(</span><span class="RktSym"><a href="Decode.html#%28def._%28%28lib._pollen%2Fdecode..rkt%29._decode-elements%29%29" class="RktValLink" data-pltdoc="x">decode-elements</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">elements</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktMeta"></span>. The <span class="RktSym">txexpr</span> package is just a more explicit way of accomplishing the task.</p></blockquote></blockquote></blockquote><p>If you run this file, what changes? Right — nothing. That’s because by default, both <span class="RktSym"><a href="Decode.html#%28def._%28%28lib._pollen%2Fdecode..rkt%29._decode-elements%29%29" class="RktValLink" data-pltdoc="x">decode-elements</a></span> (and <span class="RktSym"><a href="Decode.html#%28def._%28%28lib._pollen%2Fdecode..rkt%29._decode%29%29" class="RktValLink" data-pltdoc="x">decode</a></span>) will let the content pass through unaltered.</p><p>We change this by giving <span class="RktSym"><a href="Decode.html#%28def._%28%28lib._pollen%2Fdecode..rkt%29._decode-elements%29%29" class="RktValLink" data-pltdoc="x">decode-elements</a></span> the name of a processing function and attaching it to the type of content we want to process. In this case, we’re in luck — the <span class="RktSym"><a href="Decode.html#%28def._%28%28lib._pollen%2Fdecode..rkt%29._decode%29%29" class="RktValLink" data-pltdoc="x">decode</a></span> module already contains a <span class="RktSym"><a href="Decode.html#%28def._%28%28lib._pollen%2Fdecode..rkt%29._detect-paragraphs%29%29" class="RktValLink" data-pltdoc="x">detect-paragraphs</a></span> function (that also detects linebreaks). We add this function using the keyword argument <span class="RktPn">#:txexpr-elements-proc</span>, which is short for “the function used to process the elements of a tagged X-expression”:</p><div class="fileblock"><div class="SIntrapara"><div class="fileblock_filetitle"><span class="fileblock_filename"><span class="stt">"article.html.pm"</span></span></div></div><div class="SIntrapara"><div class="fileblock_filecontent"><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktMeta">#lang</span><span class="hspace"> </span><span class="RktMeta"></span><a href="index.html" class="RktModLink" data-pltdoc="x"><span class="RktSym">pollen</span></a><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">◊</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/require.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._require%29%29" class="RktStxLink" data-pltdoc="x">require</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">pollen/decode</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">txexpr</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta">◊</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define%29%29" class="RktStxLink" data-pltdoc="x">define</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">root</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktMeta">.</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">elements</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/txexpr/index.html#%28def._%28%28lib._txexpr%2Fmain..rkt%29._make-txexpr%29%29" class="RktValLink" data-pltdoc="x">make-txexpr</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/quote.html#%28form._%28%28quote._~23~25kernel%29._quote%29%29" class="RktStxLink" data-pltdoc="x">'</a></span><span class="RktSym">root</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#%28def._%28%28quote._~23~25kernel%29._null%29%29" class="RktValLink" data-pltdoc="x">null</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym"><a href="Decode.html#%28def._%28%28lib._pollen%2Fdecode..rkt%29._decode-elements%29%29" class="RktValLink" data-pltdoc="x">decode-elements</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">elements</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">#:txexpr-elements-proc</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym"><a href="Decode.html#%28def._%28%28lib._pollen%2Fdecode..rkt%29._detect-paragraphs%29%29" class="RktValLink" data-pltdoc="x">detect-paragraphs</a></span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">The</span><span class="hspace"> </span><span class="RktMeta">first</span><span class="hspace"> </span><span class="RktMeta">line</span><span class="hspace"> </span><span class="RktMeta">of</span><span class="hspace"> </span><span class="RktMeta">the</span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktVal">'</span><span class="RktMeta">first</span><span class="RktVal">'</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta">paragraph.</span></td></tr><tr><td><span class="RktMeta">And</span><span class="hspace"> </span><span class="RktMeta">a</span><span class="hspace"> </span><span class="RktMeta">new</span><span class="hspace"> </span><span class="RktMeta">line.</span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">The</span><span class="hspace"> </span><span class="RktMeta">second</span><span class="hspace"> </span><span class="RktMeta">paragraph</span><span class="hspace"> </span><span class="RktMeta">---</span><span class="hspace"> </span><span class="RktMeta">isn</span><span class="RktVal">'</span><span class="RktMeta">t</span><span class="hspace"> </span><span class="RktMeta">it</span><span class="hspace"> </span><span class="RktMeta">great.</span></td></tr></table></blockquote></div></div></div></div><p>Now, when we run the file, the X-expression has changed to include two <span class="RktSym">p</span> tags and a <span class="RktSym">br</span> tag:</p><blockquote class="SubFlow"><p><span class="RktVal"><span class="stt">'(root (p "The first line of the 'first' paragraph." (br) "And a new line.") (p "The second paragraph --- isn't it great."))</span></span></p></blockquote><p>That means when we convert to HTML, we get the tags we need:</p><blockquote class="SubFlow"><p><span class="RktVal"><span class="stt"><root><p>The first line of the 'first' paragraph.<br />And a new line.</p><p>The second paragraph --- isn't it great.</p></root></span></span></p></blockquote><p>So when we view this in the project server, the linebreaks and paragraph breaks are displayed correctly:</p><div class="browser"><div class="SIntrapara">The first line of the 'first' paragraph.<br/>And a new line.<br/><br/>The second paragraph --- isn't it great.</div></div><p>Of course, in practice you wouldn’t put your decoding function in a single source file. You’d make it available to all your source files by putting it in <span class="stt">directory-require.rkt</span>. So let’s do that now:</p><div class="fileblock"><div class="SIntrapara"><div class="fileblock_filetitle"><span class="fileblock_filename"><span class="stt">"directory-require.rkt"</span></span></div></div><div class="SIntrapara"><div class="fileblock_filecontent"><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktMeta">#lang</span><span class="hspace"> </span><span class="RktMeta"></span><a href="http://docs.racket-lang.org/reference/index.html" class="RktModLink" data-pltdoc="x"><span class="RktSym">racket</span></a><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/require.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._require%29%29" class="RktStxLink" data-pltdoc="x">require</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">pollen/decode</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">txexpr</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define%29%29" class="RktStxLink" data-pltdoc="x">define</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">root</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktMeta">.</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">elements</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/txexpr/index.html#%28def._%28%28lib._txexpr%2Fmain..rkt%29._make-txexpr%29%29" class="RktValLink" data-pltdoc="x">make-txexpr</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/quote.html#%28form._%28%28quote._~23~25kernel%29._quote%29%29" class="RktStxLink" data-pltdoc="x">'</a></span><span class="RktSym">root</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#%28def._%28%28quote._~23~25kernel%29._null%29%29" class="RktValLink" data-pltdoc="x">null</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym"><a href="Decode.html#%28def._%28%28lib._pollen%2Fdecode..rkt%29._decode-elements%29%29" class="RktValLink" data-pltdoc="x">decode-elements</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">elements</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">#:txexpr-elements-proc</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym"><a href="Decode.html#%28def._%28%28lib._pollen%2Fdecode..rkt%29._detect-paragraphs%29%29" class="RktValLink" data-pltdoc="x">detect-paragraphs</a></span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/require.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._provide%29%29" class="RktStxLink" data-pltdoc="x">provide</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">root</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr></table></blockquote></div></div></div></div><p>We’ll also restore the source of <span class="stt">article.html.pm</span> to its original, simplified state:</p><div class="fileblock"><div class="SIntrapara"><div class="fileblock_filetitle"><span class="fileblock_filename"><span class="stt">"article.html.pm"</span></span></div></div><div class="SIntrapara"><div class="fileblock_filecontent"><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktMeta">#lang</span><span class="hspace"> </span><span class="RktMeta"></span><a href="index.html" class="RktModLink" data-pltdoc="x"><span class="RktSym">pollen</span></a><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">The</span><span class="hspace"> </span><span class="RktMeta">first</span><span class="hspace"> </span><span class="RktMeta">line</span><span class="hspace"> </span><span class="RktMeta">of</span><span class="hspace"> </span><span class="RktMeta">the</span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktVal">'</span><span class="RktMeta">first</span><span class="RktVal">'</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta">paragraph.</span></td></tr><tr><td><span class="RktMeta">And</span><span class="hspace"> </span><span class="RktMeta">a</span><span class="hspace"> </span><span class="RktMeta">new</span><span class="hspace"> </span><span class="RktMeta">line.</span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">The</span><span class="hspace"> </span><span class="RktMeta">second</span><span class="hspace"> </span><span class="RktMeta">paragraph</span><span class="hspace"> </span><span class="RktMeta">---</span><span class="hspace"> </span><span class="RktMeta">isn</span><span class="RktVal">'</span><span class="RktMeta">t</span><span class="hspace"> </span><span class="RktMeta">it</span><span class="hspace"> </span><span class="RktMeta">great.</span></td></tr></table></blockquote></div></div></div></div><p>And the result in the project server will be the same:</p><div class="browser"><div class="SIntrapara">The first line of the 'first' paragraph.<br/>And a new line.<br/><br/>The second paragraph --- isn't it great.</div></div><p>But wait, those straight quotes look terrible. Also, three hyphens for an em dash? Barbaric.</p><p>Let’s upgrade our decoder to take of those. Once again, we’ll get lucky, because the <span class="RktSym"><a href="Decode.html#%28def._%28%28lib._pollen%2Fdecode..rkt%29._decode%29%29" class="RktValLink" data-pltdoc="x">decode</a></span> module provides two functions for the job: <span class="RktSym"><a href="Decode.html#%28def._%28%28lib._pollen%2Fdecode..rkt%29._smart-quotes%29%29" class="RktValLink" data-pltdoc="x">smart-quotes</a></span> and <span class="RktSym"><a href="Decode.html#%28def._%28%28lib._pollen%2Fdecode..rkt%29._smart-dashes%29%29" class="RktValLink" data-pltdoc="x">smart-dashes</a></span>.</p><p>This time, however, we’re going to attach them to another part of <span class="RktSym"><a href="Decode.html#%28def._%28%28lib._pollen%2Fdecode..rkt%29._decode-elements%29%29" class="RktValLink" data-pltdoc="x">decode-elements</a></span>. Smart-quote and smart-dash conversion only needs to look at the strings within the X-expression. So instead of attaching these functions to the <span class="RktPn">#:txexpr-elements-proc</span> argument of <span class="RktSym"><a href="Decode.html#%28def._%28%28lib._pollen%2Fdecode..rkt%29._decode-elements%29%29" class="RktValLink" data-pltdoc="x">decode-elements</a></span>, we’ll attach them to <span class="RktPn">#:string-proc</span>, which lets us specify a function to apply to strings:</p><div class="fileblock"><div class="SIntrapara"><div class="fileblock_filetitle"><span class="fileblock_filename"><span class="stt">"directory-require.rkt"</span></span></div></div><div class="SIntrapara"><div class="fileblock_filecontent"><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktMeta">#lang</span><span class="hspace"> </span><span class="RktMeta"></span><a href="http://docs.racket-lang.org/reference/index.html" class="RktModLink" data-pltdoc="x"><span class="RktSym">racket/base</span></a><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/require.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._require%29%29" class="RktStxLink" data-pltdoc="x">require</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">pollen/decode</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">txexpr</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define%29%29" class="RktStxLink" data-pltdoc="x">define</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">root</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktMeta">.</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">elements</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/txexpr/index.html#%28def._%28%28lib._txexpr%2Fmain..rkt%29._make-txexpr%29%29" class="RktValLink" data-pltdoc="x">make-txexpr</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/quote.html#%28form._%28%28quote._~23~25kernel%29._quote%29%29" class="RktStxLink" data-pltdoc="x">'</a></span><span class="RktSym">root</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#%28def._%28%28quote._~23~25kernel%29._null%29%29" class="RktValLink" data-pltdoc="x">null</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym"><a href="Decode.html#%28def._%28%28lib._pollen%2Fdecode..rkt%29._decode-elements%29%29" class="RktValLink" data-pltdoc="x">decode-elements</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">elements</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">#:txexpr-elements-proc</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym"><a href="Decode.html#%28def._%28%28lib._pollen%2Fdecode..rkt%29._detect-paragraphs%29%29" class="RktValLink" data-pltdoc="x">detect-paragraphs</a></span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">#:string-proc</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/procedures.html#%28def._%28%28lib._racket%2Fprivate%2Flist..rkt%29._compose%29%29" class="RktValLink" data-pltdoc="x">compose</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym"><a href="Decode.html#%28def._%28%28lib._pollen%2Fdecode..rkt%29._smart-quotes%29%29" class="RktValLink" data-pltdoc="x">smart-quotes</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym"><a href="Decode.html#%28def._%28%28lib._pollen%2Fdecode..rkt%29._smart-dashes%29%29" class="RktValLink" data-pltdoc="x">smart-dashes</a></span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/require.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._provide%29%29" class="RktStxLink" data-pltdoc="x">provide</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">root</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr></table></blockquote></div></div></div></div><p>Because <span class="RktPn">#:string-proc</span> only accepts one function (not two), we need to use <span class="RktSym"><a href="http://docs.racket-lang.org/reference/procedures.html#%28def._%28%28lib._racket%2Fprivate%2Flist..rkt%29._compose%29%29" class="RktValLink" data-pltdoc="x">compose</a></span> to combine <span class="RktSym"><a href="Decode.html#%28def._%28%28lib._pollen%2Fdecode..rkt%29._smart-quotes%29%29" class="RktValLink" data-pltdoc="x">smart-quotes</a></span> and <span class="RktSym"><a href="Decode.html#%28def._%28%28lib._pollen%2Fdecode..rkt%29._smart-dashes%29%29" class="RktValLink" data-pltdoc="x">smart-dashes</a></span> into one (<span class="RktSym"><a href="http://docs.racket-lang.org/reference/procedures.html#%28def._%28%28lib._racket%2Fprivate%2Flist..rkt%29._compose%29%29" class="RktValLink" data-pltdoc="x">compose</a></span> will apply the last function, then the previous one, and so on to the left end of the list).</p><p>Now, if we run <span class="stt">article.html.pm</span> in DrRacket, we can see the effects of the new decoder functions. The quotes are curled, and the three hyphens become an em dash:</p><blockquote class="SubFlow"><p><span class="RktVal"><span class="stt">'(root (p "The first line of the ‘first’ paragraph." (br) "And a new line.") (p "The second paragraph—isn’t it great."))</span></span></p></blockquote><p>And of course, this shows up in the project server too:</p><div class="browser"><div class="SIntrapara">The first line of the ‘first’ paragraph.<br/>And a new line.<br/><br/>The second paragraph—isn’t it great.</div></div><p>By the way, even though decoding via the <span class="stt">root</span> tag is the most likely usage scenario, you don’t have to do it that way. Decoding is just a special kind of tag function. So you can make a decoder that only affects a certain tag within the page. Or you can make multiple decoders for different tags. The advantage of using a decoder with <span class="stt">root</span> is that it can affect all the content, and since it’s attached to the root node, it will always be the last tag function that gets called.</p><h4>7.8<tt> </tt><a name="(part._.Putting_it_all_together)"></a>Putting it all together</h4><p>For this final example, we’ll combine what we’ve learned in the first three tutorials. Though this project is still simple, it summarizes all the major concepts of Pollen.</p><p>It also provides a recipe you can adapt for your own projects, whether small or large. For instance, <span style="font-style: italic"><a href="http://practicaltypography.com">Butterick’s Practical Typography</a></span> follows this core structure.</p><p>As we go through the ingredients, I’ll review the purpose of each. Save these files into a single project directory with the project server running.</p><h5>7.8.1<tt> </tt><a name="(part._tutorial-3._.The_directory-require_rkt_file)"></a>The <span class="stt">directory-require.rkt</span> file</h5><p>This file provides functions that are available to all Pollen source files in the same directory. It’s written in standard Racket. The <span class="stt">directory-require.rkt</span> file is optional — without it, your tags will just be treated as default tag functions. But you’ll probably find it a convenient way to make tag functions available within your project, including a <span class="RktSym"><a href="Decode.html#%28def._%28%28lib._pollen%2Fdecode..rkt%29._decode%29%29" class="RktValLink" data-pltdoc="x">decode</a></span> function attached to <span class="stt">root</span>.</p><p>Here, we’ll use the <span class="stt">directory-require.rkt</span> we devised in the previous section to set up decoding for our source files:</p><div class="fileblock"><div class="SIntrapara"><div class="fileblock_filetitle"><span class="fileblock_filename"><span class="stt">"directory-require.rkt"</span></span></div></div><div class="SIntrapara"><div class="fileblock_filecontent"><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktMeta">#lang</span><span class="hspace"> </span><span class="RktMeta"></span><a href="http://docs.racket-lang.org/reference/index.html" class="RktModLink" data-pltdoc="x"><span class="RktSym">racket/base</span></a><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/require.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._require%29%29" class="RktStxLink" data-pltdoc="x">require</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">pollen/decode</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">txexpr</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define%29%29" class="RktStxLink" data-pltdoc="x">define</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">root</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktMeta">.</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">elements</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/txexpr/index.html#%28def._%28%28lib._txexpr%2Fmain..rkt%29._make-txexpr%29%29" class="RktValLink" data-pltdoc="x">make-txexpr</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/quote.html#%28form._%28%28quote._~23~25kernel%29._quote%29%29" class="RktStxLink" data-pltdoc="x">'</a></span><span class="RktSym">root</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#%28def._%28%28quote._~23~25kernel%29._null%29%29" class="RktValLink" data-pltdoc="x">null</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym"><a href="Decode.html#%28def._%28%28lib._pollen%2Fdecode..rkt%29._decode-elements%29%29" class="RktValLink" data-pltdoc="x">decode-elements</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">elements</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">#:txexpr-elements-proc</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym"><a href="Decode.html#%28def._%28%28lib._pollen%2Fdecode..rkt%29._detect-paragraphs%29%29" class="RktValLink" data-pltdoc="x">detect-paragraphs</a></span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">#:string-proc</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/procedures.html#%28def._%28%28lib._racket%2Fprivate%2Flist..rkt%29._compose%29%29" class="RktValLink" data-pltdoc="x">compose</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym"><a href="Decode.html#%28def._%28%28lib._pollen%2Fdecode..rkt%29._smart-quotes%29%29" class="RktValLink" data-pltdoc="x">smart-quotes</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym"><a href="Decode.html#%28def._%28%28lib._pollen%2Fdecode..rkt%29._smart-dashes%29%29" class="RktValLink" data-pltdoc="x">smart-dashes</a></span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/require.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._provide%29%29" class="RktStxLink" data-pltdoc="x">provide</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">root</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr></table></blockquote></div></div></div></div><h5>7.8.2<tt> </tt><a name="(part._.The_template)"></a>The template</h5><p>When you’re using Pollen authoring mode for your content — using either Markdown syntax, or Pollen markup — your source files will produce an X-expression. To convert this X-expression into a finished file, you need to use a template.</p><p>By default, when Pollen finds a source file called <span class="stt">filename.ext.pm</span> or <span class="stt">filename.ext.pmd</span>, it will look for a template in your project directory called <span class="stt">template.ext</span>, where <span class="stt">.ext</span> is the matching output extension.</p><p>In this project, we want to end up with HTML, so our source files will be called <span class="stt">filename.html.pm</span>, and thus we need to make a <span class="stt">template.html</span>. Let’s use a modified version of the one we made in the second tutorial:</p><div class="fileblock"><div class="SIntrapara"><div class="fileblock_filetitle"><span class="fileblock_filename"><span class="stt">"template.html"</span></span></div></div><div class="SIntrapara"><div class="fileblock_filecontent"><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktMeta"><html></span></td></tr><tr><td><span class="RktMeta"><head></span></td></tr><tr><td><span class="RktMeta"><meta</span><span class="hspace"> </span><span class="RktMeta">charset=</span><span class="RktVal">"UTF-8"</span><span class="RktMeta">></span></td></tr><tr><td><span class="RktMeta"><title>◊</span><span class="RktSym"><a href="Template.html#%28def._%28%28lib._pollen%2Ftemplate..rkt%29._select%29%29" class="RktValLink" data-pltdoc="x">select</a></span><span class="RktPn">[</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/quote.html#%28form._%28%28quote._~23~25kernel%29._quote%29%29" class="RktStxLink" data-pltdoc="x">'</a></span><span class="RktSym">h1</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">doc</span><span class="RktPn">]</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta">by</span><span class="hspace"> </span><span class="RktMeta">T.</span><span class="hspace"> </span><span class="RktMeta">S.</span><span class="hspace"> </span><span class="RktMeta">Eliot</title></span></td></tr><tr><td><span class="RktMeta"><link</span><span class="hspace"> </span><span class="RktMeta">rel=</span><span class="RktVal">"stylesheet"</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta">type=</span><span class="RktVal">"text/css"</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta">media=</span><span class="RktVal">"all"</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta">href=</span><span class="RktVal">"styles.css"</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta">/></span></td></tr><tr><td><span class="RktMeta"></head></span></td></tr><tr><td><span class="RktMeta"><body>◊</span><span class="RktSym"><a href="Template.html#%28def._%28%28lib._pollen%2Ftemplate..rkt%29._-~3ehtml%29%29" class="RktValLink" data-pltdoc="x"><span class="nobreak">-></span>html</a></span><span class="RktPn">[</span><span class="RktSym">doc</span><span class="RktPn">]</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta">◊</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define%29%29" class="RktStxLink" data-pltdoc="x">define</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">prev-page</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">previous</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">here</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta">◊</span><span class="RktSym"><a href="Template.html#%28def._%28%28lib._pollen%2Ftemplate..rkt%29._when%2Fblock%29%29" class="RktValLink" data-pltdoc="x">when/block</a></span><span class="RktPn">[</span><span class="RktSym">prev-page</span><span class="RktPn">]</span><span class="RktPn">{</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"><div</span><span class="hspace"> </span><span class="RktMeta">id=</span><span class="RktVal">"prev"</span><span class="RktMeta">>← <a</span><span class="hspace"> </span><span class="RktMeta">href=</span><span class="RktVal">"◊|prev-page|"</span><span class="RktMeta">>◊</span><span class="RktPn">(</span><span class="RktSym"><a href="Template.html#%28def._%28%28lib._pollen%2Ftemplate..rkt%29._select%29%29" class="RktValLink" data-pltdoc="x">select</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/quote.html#%28form._%28%28quote._~23~25kernel%29._quote%29%29" class="RktStxLink" data-pltdoc="x">'</a></span><span class="RktSym">h1</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">prev-page</span><span class="RktPn">)</span><span class="RktMeta"></a></div></span><span class="RktPn">}</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta">◊</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define%29%29" class="RktStxLink" data-pltdoc="x">define</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">next-page</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">next</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">here</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta">◊</span><span class="RktSym"><a href="Template.html#%28def._%28%28lib._pollen%2Ftemplate..rkt%29._when%2Fblock%29%29" class="RktValLink" data-pltdoc="x">when/block</a></span><span class="RktPn">[</span><span class="RktSym">next-page</span><span class="RktPn">]</span><span class="RktPn">{</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"><div</span><span class="hspace"> </span><span class="RktMeta">id=</span><span class="RktVal">"next"</span><span class="RktMeta">><a</span><span class="hspace"> </span><span class="RktMeta">href=</span><span class="RktVal">"◊|next-page|"</span><span class="RktMeta">>◊</span><span class="RktPn">(</span><span class="RktSym"><a href="Template.html#%28def._%28%28lib._pollen%2Ftemplate..rkt%29._select%29%29" class="RktValLink" data-pltdoc="x">select</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/quote.html#%28form._%28%28quote._~23~25kernel%29._quote%29%29" class="RktStxLink" data-pltdoc="x">'</a></span><span class="RktSym">h1</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">next-page</span><span class="RktPn">)</span><span class="RktMeta"></a> →</div></span><span class="RktPn">}</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></body></span></td></tr><tr><td><span class="RktMeta"></html></span></td></tr></table></blockquote></div></div></div></div><h5>7.8.3<tt> </tt><a name="(part._.The_pagetree)"></a>The pagetree</h5><p>A pagetree defines sequential and hierarchical relationships among a set of output files. The pagetree is used by the template to calculate navigational links (e.g., previous, next, up, etc.) A pagetree is optional — if you don’t need navigation in your project, you don’t need a pagetree.</p><p>But in this project, we do want navigation. So we’ll add an <span class="stt">index.ptree</span> file like so:</p><div class="fileblock"><div class="SIntrapara"><div class="fileblock_filetitle"><span class="fileblock_filename"><span class="stt">"index.ptree"</span></span></div></div><div class="SIntrapara"><div class="fileblock_filecontent"><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktMeta">#lang</span><span class="hspace"> </span><span class="RktMeta"></span><a href="index.html" class="RktModLink" data-pltdoc="x"><span class="RktSym">pollen</span></a><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">burial.html</span></td></tr><tr><td><span class="RktMeta">chess.html</span></td></tr><tr><td><span class="RktMeta">sermon.html</span></td></tr></table></blockquote></div></div></div></div><h5>7.8.4<tt> </tt><a name="(part._.A_.C.S.S_stylesheet_using_the_preprocessor)"></a>A CSS stylesheet using the preprocessor</h5><p>Our template file above refers to a CSS file called <span class="stt">styles.css</span>. When resolving linked files, the project server makes no distinction between static and dynamic files. If there’s a static file called <span class="stt">styles.css</span>, it will use that.</p><p>Or, if you make a preprocessor source file called <span class="stt">styles.css.pp</span>, it will be dynamically rendered into the requested <span class="stt">styles.css</span> file. The preprocessor will operate on any file with the <span class="stt">.pp</span> extension — so a preprocessor source called <span class="stt">filename.ext.pp</span> will be rendered into <span class="stt">filename.ext</span>. (The corollary is that preprocessor functionality can be added to <span style="font-style: italic">any</span> kind of text-based file.)</p><p>Preprocessor source files, like authoring source files, get access to everything in <span class="stt">directory-require.rkt</span>, so you can share common functions and variables.</p><p>Let’s use an improved version of the dynamic CSS file we made in the first tutorial.</p><div class="fileblock"><div class="SIntrapara"><div class="fileblock_filetitle"><span class="fileblock_filename"><span class="stt">"styles.css.pp"</span></span></div></div><div class="SIntrapara"><div class="fileblock_filecontent"><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktMeta">#lang</span><span class="hspace"> </span><span class="RktMeta"></span><a href="index.html" class="RktModLink" data-pltdoc="x"><span class="RktSym">pollen</span></a><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">◊</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define%29%29" class="RktStxLink" data-pltdoc="x">define</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">inner</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktVal">2</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta">◊</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define%29%29" class="RktStxLink" data-pltdoc="x">define</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">edge</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/generic-numbers.html#%28def._%28%28quote._~23~25kernel%29._%2A%29%29" class="RktValLink" data-pltdoc="x">*</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">inner</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktVal">2</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta">◊</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define%29%29" class="RktStxLink" data-pltdoc="x">define</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">color</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktVal">"gray"</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta">◊</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define%29%29" class="RktStxLink" data-pltdoc="x">define</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">multiplier</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktVal">1.3</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">body</span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">{</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta">margin:</span><span class="hspace"> </span><span class="RktMeta">◊|</span><span class="RktSym">edge</span><span class="RktMeta">|em</span><span class="RktCmt">;</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta">border:</span><span class="hspace"> </span><span class="RktMeta">◊|</span><span class="RktSym">inner</span><span class="RktMeta">|em</span><span class="hspace"> </span><span class="RktMeta">double</span><span class="hspace"> </span><span class="RktMeta">◊|</span><span class="RktSym">color</span><span class="RktMeta">|</span><span class="RktCmt">;</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta">padding:</span><span class="hspace"> </span><span class="RktMeta">◊|</span><span class="RktSym">inner</span><span class="RktMeta">|em</span><span class="RktCmt">;</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta">font-size:</span><span class="hspace"> </span><span class="RktMeta">◊|</span><span class="RktSym">multiplier</span><span class="RktMeta">|em</span><span class="RktCmt">;</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta">line-height:</span><span class="hspace"> </span><span class="RktMeta">◊|</span><span class="RktSym">multiplier</span><span class="RktMeta">|</span><span class="RktCmt">;</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktPn">}</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta">h1</span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">{</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta">font-size:</span><span class="hspace"> </span><span class="RktMeta">◊|</span><span class="RktSym">multiplier</span><span class="RktMeta">|em</span><span class="RktCmt">;</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktPn">}</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta">#prev</span><span class="RktMeta">,</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktMeta">#next</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">{</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta">position:</span><span class="hspace"> </span><span class="RktMeta">fixed</span><span class="RktCmt">;</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta">top:</span><span class="hspace"> </span><span class="RktMeta">◊|(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/generic-numbers.html#%28def._%28%28quote._~23~25kernel%29._%2F%29%29" class="RktValLink" data-pltdoc="x">/</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">edge</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta">2)|em</span><span class="RktCmt">;</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktPn">}</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta">#prev</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">{</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta">left:</span><span class="hspace"> </span><span class="RktMeta">◊|</span><span class="RktSym">edge</span><span class="RktMeta">|em</span><span class="RktCmt">;</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktPn">}</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"> </span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta">#next</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">{</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta">right:</span><span class="hspace"> </span><span class="RktMeta">◊|</span><span class="RktSym">edge</span><span class="RktMeta">|em</span><span class="RktCmt">;</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktPn">}</span><span class="RktMeta"></span></td></tr></table></blockquote></div></div></div></div><h5>7.8.5<tt> </tt><a name="(part._.The_content_source_files_using_.Pollen_markup)"></a>The content source files using Pollen markup</h5><p>With the scaffolding in place, we need the content. Our pagetree contains three output files — <span class="stt">burial.html</span>, <span class="stt">chess.html</span>, and <span class="stt">sermon.html</span>. We’re going to make these output files using Pollen markup. So we’ll create three source files and name them by adding the <span class="stt">.pm</span> source extension to each of the output names — thus <span class="stt">burial.html.pm</span>, <span class="stt">chess.html.pm</span>, and <span class="stt">sermon.html.pm</span>, as follows (and with apologies to T. S. Eliot):</p><div class="fileblock"><div class="SIntrapara"><div class="fileblock_filetitle"><span class="fileblock_filename"><span class="stt">"burial.html.pm"</span></span></div></div><div class="SIntrapara"><div class="fileblock_filecontent"><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktMeta"></span><span class="RktMeta">#lang</span><span class="hspace"> </span><span class="RktMeta">pollen</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta"> </span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta">◊h1{I.</span><span class="hspace"> </span><span class="RktMeta">The</span><span class="hspace"> </span><span class="RktMeta">Burial</span><span class="hspace"> </span><span class="RktMeta">of</span><span class="hspace"> </span><span class="RktMeta">the</span><span class="hspace"> </span><span class="RktMeta">Dead}</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta"> </span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta">"You</span><span class="hspace"> </span><span class="RktMeta">gave</span><span class="hspace"> </span><span class="RktMeta">me</span><span class="hspace"> </span><span class="RktMeta">hyacinths</span><span class="hspace"> </span><span class="RktMeta">first</span><span class="hspace"> </span><span class="RktMeta">a</span><span class="hspace"> </span><span class="RktMeta">year</span><span class="hspace"> </span><span class="RktMeta">ago;</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta">They</span><span class="hspace"> </span><span class="RktMeta">called</span><span class="hspace"> </span><span class="RktMeta">me</span><span class="hspace"> </span><span class="RktMeta">the</span><span class="hspace"> </span><span class="RktMeta">hyacinth</span><span class="hspace"> </span><span class="RktMeta">girl."</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta">---</span><span class="hspace"> </span><span class="RktMeta">Yet</span><span class="hspace"> </span><span class="RktMeta">when</span><span class="hspace"> </span><span class="RktMeta">we</span><span class="hspace"> </span><span class="RktMeta">came</span><span class="hspace"> </span><span class="RktMeta">back,</span><span class="hspace"> </span><span class="RktMeta">late,</span><span class="hspace"> </span><span class="RktMeta">from</span><span class="hspace"> </span><span class="RktMeta">the</span><span class="hspace"> </span><span class="RktMeta">Hyacinth</span><span class="hspace"> </span><span class="RktMeta">garden,</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta">Your</span><span class="hspace"> </span><span class="RktMeta">arms</span><span class="hspace"> </span><span class="RktMeta">full,</span><span class="hspace"> </span><span class="RktMeta">and</span><span class="hspace"> </span><span class="RktMeta">your</span><span class="hspace"> </span><span class="RktMeta">hair</span><span class="hspace"> </span><span class="RktMeta">wet,</span><span class="hspace"> </span><span class="RktMeta">I</span><span class="hspace"> </span><span class="RktMeta">could</span><span class="hspace"> </span><span class="RktMeta">not</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta">Speak,</span><span class="hspace"> </span><span class="RktMeta">and</span><span class="hspace"> </span><span class="RktMeta">my</span><span class="hspace"> </span><span class="RktMeta">eyes</span><span class="hspace"> </span><span class="RktMeta">failed,</span><span class="hspace"> </span><span class="RktMeta">I</span><span class="hspace"> </span><span class="RktMeta">was</span><span class="hspace"> </span><span class="RktMeta">neither</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta">Living</span><span class="hspace"> </span><span class="RktMeta">nor</span><span class="hspace"> </span><span class="RktMeta">dead,</span><span class="hspace"> </span><span class="RktMeta">and</span><span class="hspace"> </span><span class="RktMeta">I</span><span class="hspace"> </span><span class="RktMeta">knew</span><span class="hspace"> </span><span class="RktMeta">nothing,</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta">Looking</span><span class="hspace"> </span><span class="RktMeta">into</span><span class="hspace"> </span><span class="RktMeta">the</span><span class="hspace"> </span><span class="RktMeta">heart</span><span class="hspace"> </span><span class="RktMeta">of</span><span class="hspace"> </span><span class="RktMeta">light,</span><span class="hspace"> </span><span class="RktMeta">the</span><span class="hspace"> </span><span class="RktMeta">silence.</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta">◊em{Od'</span><span class="hspace"> </span><span class="RktMeta">und</span><span class="hspace"> </span><span class="RktMeta">leer</span><span class="hspace"> </span><span class="RktMeta">das</span><span class="hspace"> </span><span class="RktMeta">Meer.}</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta"> </span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta">Madame</span><span class="hspace"> </span><span class="RktMeta">Sosostris,</span><span class="hspace"> </span><span class="RktMeta">famous</span><span class="hspace"> </span><span class="RktMeta">clairvoyante,</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta">Had</span><span class="hspace"> </span><span class="RktMeta">a</span><span class="hspace"> </span><span class="RktMeta">bad</span><span class="hspace"> </span><span class="RktMeta">cold,</span><span class="hspace"> </span><span class="RktMeta">nevertheless</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta">Is</span><span class="hspace"> </span><span class="RktMeta">known</span><span class="hspace"> </span><span class="RktMeta">to</span><span class="hspace"> </span><span class="RktMeta">be</span><span class="hspace"> </span><span class="RktMeta">the</span><span class="hspace"> </span><span class="RktMeta">wisest</span><span class="hspace"> </span><span class="RktMeta">woman</span><span class="hspace"> </span><span class="RktMeta">in</span><span class="hspace"> </span><span class="RktMeta">Europe,</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta">With</span><span class="hspace"> </span><span class="RktMeta">a</span><span class="hspace"> </span><span class="RktMeta">wicked</span><span class="hspace"> </span><span class="RktMeta">pack</span><span class="hspace"> </span><span class="RktMeta">of</span><span class="hspace"> </span><span class="RktMeta">cards.</span><span class="RktMeta"></span></td></tr></table></blockquote></div></div></div></div><div class="fileblock"><div class="SIntrapara"><div class="fileblock_filetitle"><span class="fileblock_filename"><span class="stt">"chess.html.pm"</span></span></div></div><div class="SIntrapara"><div class="fileblock_filecontent"><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktMeta"></span><span class="RktMeta">#lang</span><span class="hspace"> </span><span class="RktMeta">pollen</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta"> </span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta">◊h1{II.</span><span class="hspace"> </span><span class="RktMeta">A</span><span class="hspace"> </span><span class="RktMeta">Game</span><span class="hspace"> </span><span class="RktMeta">of</span><span class="hspace"> </span><span class="RktMeta">Chess}</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta"> </span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta">And</span><span class="hspace"> </span><span class="RktMeta">still</span><span class="hspace"> </span><span class="RktMeta">she</span><span class="hspace"> </span><span class="RktMeta">cried,</span><span class="hspace"> </span><span class="RktMeta">and</span><span class="hspace"> </span><span class="RktMeta">still</span><span class="hspace"> </span><span class="RktMeta">the</span><span class="hspace"> </span><span class="RktMeta">world</span><span class="hspace"> </span><span class="RktMeta">pursues,</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta">"Jug</span><span class="hspace"> </span><span class="RktMeta">Jug"</span><span class="hspace"> </span><span class="RktMeta">to</span><span class="hspace"> </span><span class="RktMeta">dirty</span><span class="hspace"> </span><span class="RktMeta">ears.</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta">And</span><span class="hspace"> </span><span class="RktMeta">other</span><span class="hspace"> </span><span class="RktMeta">withered</span><span class="hspace"> </span><span class="RktMeta">stumps</span><span class="hspace"> </span><span class="RktMeta">of</span><span class="hspace"> </span><span class="RktMeta">time</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta">Were</span><span class="hspace"> </span><span class="RktMeta">told</span><span class="hspace"> </span><span class="RktMeta">upon</span><span class="hspace"> </span><span class="RktMeta">the</span><span class="hspace"> </span><span class="RktMeta">walls;</span><span class="hspace"> </span><span class="RktMeta">staring</span><span class="hspace"> </span><span class="RktMeta">forms</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta">Leaned</span><span class="hspace"> </span><span class="RktMeta">out,</span><span class="hspace"> </span><span class="RktMeta">leaning,</span><span class="hspace"> </span><span class="RktMeta">hushing</span><span class="hspace"> </span><span class="RktMeta">the</span><span class="hspace"> </span><span class="RktMeta">room</span><span class="hspace"> </span><span class="RktMeta">enclosed.</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta">Footsteps</span><span class="hspace"> </span><span class="RktMeta">shuffled</span><span class="hspace"> </span><span class="RktMeta">on</span><span class="hspace"> </span><span class="RktMeta">the</span><span class="hspace"> </span><span class="RktMeta">stair,</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta">Under</span><span class="hspace"> </span><span class="RktMeta">the</span><span class="hspace"> </span><span class="RktMeta">firelight,</span><span class="hspace"> </span><span class="RktMeta">under</span><span class="hspace"> </span><span class="RktMeta">the</span><span class="hspace"> </span><span class="RktMeta">brush,</span><span class="hspace"> </span><span class="RktMeta">her</span><span class="hspace"> </span><span class="RktMeta">hair</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta">Spread</span><span class="hspace"> </span><span class="RktMeta">out</span><span class="hspace"> </span><span class="RktMeta">in</span><span class="hspace"> </span><span class="RktMeta">fiery</span><span class="hspace"> </span><span class="RktMeta">points</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta">Glowed</span><span class="hspace"> </span><span class="RktMeta">into</span><span class="hspace"> </span><span class="RktMeta">words,</span><span class="hspace"> </span><span class="RktMeta">then</span><span class="hspace"> </span><span class="RktMeta">would</span><span class="hspace"> </span><span class="RktMeta">be</span><span class="hspace"> </span><span class="RktMeta">savagely</span><span class="hspace"> </span><span class="RktMeta">still.</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta"> </span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta">"My</span><span class="hspace"> </span><span class="RktMeta">nerves</span><span class="hspace"> </span><span class="RktMeta">are</span><span class="hspace"> </span><span class="RktMeta">bad</span><span class="hspace"> </span><span class="RktMeta">to-night.</span><span class="hspace"> </span><span class="RktMeta">Yes,</span><span class="hspace"> </span><span class="RktMeta">bad.</span><span class="hspace"> </span><span class="RktMeta">Stay</span><span class="hspace"> </span><span class="RktMeta">with</span><span class="hspace"> </span><span class="RktMeta">me.</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta">Speak</span><span class="hspace"> </span><span class="RktMeta">to</span><span class="hspace"> </span><span class="RktMeta">me.</span><span class="hspace"> </span><span class="RktMeta">Why</span><span class="hspace"> </span><span class="RktMeta">do</span><span class="hspace"> </span><span class="RktMeta">you</span><span class="hspace"> </span><span class="RktMeta">never</span><span class="hspace"> </span><span class="RktMeta">speak?</span><span class="hspace"> </span><span class="RktMeta">Speak.</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta">What</span><span class="hspace"> </span><span class="RktMeta">are</span><span class="hspace"> </span><span class="RktMeta">you</span><span class="hspace"> </span><span class="RktMeta">thinking</span><span class="hspace"> </span><span class="RktMeta">of?</span><span class="hspace"> </span><span class="RktMeta">What</span><span class="hspace"> </span><span class="RktMeta">thinking?</span><span class="hspace"> </span><span class="RktMeta">What?</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta">I</span><span class="hspace"> </span><span class="RktMeta">never</span><span class="hspace"> </span><span class="RktMeta">know</span><span class="hspace"> </span><span class="RktMeta">what</span><span class="hspace"> </span><span class="RktMeta">you</span><span class="hspace"> </span><span class="RktMeta">are</span><span class="hspace"> </span><span class="RktMeta">thinking.</span><span class="hspace"> </span><span class="RktMeta">Think."</span><span class="RktMeta"></span></td></tr></table></blockquote></div></div></div></div><div class="fileblock"><div class="SIntrapara"><div class="fileblock_filetitle"><span class="fileblock_filename"><span class="stt">"sermon.html.pm"</span></span></div></div><div class="SIntrapara"><div class="fileblock_filecontent"><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktMeta"></span><span class="RktMeta">#lang</span><span class="hspace"> </span><span class="RktMeta">pollen</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta"> </span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta">◊h1{III.</span><span class="hspace"> </span><span class="RktMeta">The</span><span class="hspace"> </span><span class="RktMeta">Fire</span><span class="hspace"> </span><span class="RktMeta">Sermon}</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta"> </span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta">"Trams</span><span class="hspace"> </span><span class="RktMeta">and</span><span class="hspace"> </span><span class="RktMeta">dusty</span><span class="hspace"> </span><span class="RktMeta">trees.</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta">Highbury</span><span class="hspace"> </span><span class="RktMeta">bore</span><span class="hspace"> </span><span class="RktMeta">me.</span><span class="hspace"> </span><span class="RktMeta">Richmond</span><span class="hspace"> </span><span class="RktMeta">and</span><span class="hspace"> </span><span class="RktMeta">Kew</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta">Undid</span><span class="hspace"> </span><span class="RktMeta">me.</span><span class="hspace"> </span><span class="RktMeta">By</span><span class="hspace"> </span><span class="RktMeta">Richmond</span><span class="hspace"> </span><span class="RktMeta">I</span><span class="hspace"> </span><span class="RktMeta">raised</span><span class="hspace"> </span><span class="RktMeta">my</span><span class="hspace"> </span><span class="RktMeta">knees</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta">Supine</span><span class="hspace"> </span><span class="RktMeta">on</span><span class="hspace"> </span><span class="RktMeta">the</span><span class="hspace"> </span><span class="RktMeta">floor</span><span class="hspace"> </span><span class="RktMeta">of</span><span class="hspace"> </span><span class="RktMeta">a</span><span class="hspace"> </span><span class="RktMeta">narrow</span><span class="hspace"> </span><span class="RktMeta">canoe."</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta"> </span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta">"My</span><span class="hspace"> </span><span class="RktMeta">feet</span><span class="hspace"> </span><span class="RktMeta">are</span><span class="hspace"> </span><span class="RktMeta">at</span><span class="hspace"> </span><span class="RktMeta">Moorgate,</span><span class="hspace"> </span><span class="RktMeta">and</span><span class="hspace"> </span><span class="RktMeta">my</span><span class="hspace"> </span><span class="RktMeta">heart</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta">Under</span><span class="hspace"> </span><span class="RktMeta">my</span><span class="hspace"> </span><span class="RktMeta">feet.</span><span class="hspace"> </span><span class="RktMeta">After</span><span class="hspace"> </span><span class="RktMeta">the</span><span class="hspace"> </span><span class="RktMeta">event</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta">He</span><span class="hspace"> </span><span class="RktMeta">wept.</span><span class="hspace"> </span><span class="RktMeta">He</span><span class="hspace"> </span><span class="RktMeta">promised</span><span class="hspace"> </span><span class="RktMeta">'a</span><span class="hspace"> </span><span class="RktMeta">new</span><span class="hspace"> </span><span class="RktMeta">start.'</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktMeta">I</span><span class="hspace"> </span><span class="RktMeta">made</span><span class="hspace"> </span><span class="RktMeta">no</span><span class="hspace"> </span><span class="RktMeta">comment.</span><span class="hspace"> </span><span class="RktMeta">What</span><span class="hspace"> </span><span class="RktMeta">should</span><span class="hspace"> </span><span class="RktMeta">I</span><span class="hspace"> </span><span class="RktMeta">resent?"</span><span class="RktMeta"></span></td></tr></table></blockquote></div></div></div></div><h5>7.8.6<tt> </tt><a name="(part._.The_result)"></a>The result</h5><p>Now visit the project server and view <span class="stt">burial.html</span>, which should look something like this (the box will expand to fit your browser window):</p><p><img src="burial.png" alt="" width="672" height="646"/></p><p>Click the navigational links at the top to move between pages. You’re encouraged to change the source files, the style sheet, the template, or <span class="stt">directory-require.rkt</span>, and see how these changes immediately affect the page rendering in the project server. (You can also change the sequence of the pages in <span class="stt">index.ptree</span>, but in that case, you’ll need to restart the project server to see the change.)</p><p>This page isn’t a miracle of web design, but it shows you in one example:</p><ul><li><p>Pollen markup being decoded — paragraph breaks, linebreaks, smart quotes, smart dashes — with a <span class="RktSym"><a href="Decode.html#%28def._%28%28lib._pollen%2Fdecode..rkt%29._decode%29%29" class="RktValLink" data-pltdoc="x">decode</a></span> function attached to the <span class="stt">root</span> node by <span class="stt">directory-require.rkt</span>;</p></li><li><p>A dynamically-generated CSS file that computes positions for CSS elements using numerical values set up with <span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define%29%29" class="RktStxLink" data-pltdoc="x">define</a></span>, and mathematical conversions thereof;</p></li><li><p>Navigational links that appear and disappear as needed using conditional statements (<span class="RktSym"><a href="Template.html#%28def._%28%28lib._pollen%2Ftemplate..rkt%29._when%2Fblock%29%29" class="RktValLink" data-pltdoc="x">when/block</a></span>) in <span class="stt">template.html</span>, with the page sequence defined by <span class="stt">index.ptree</span> and the names of the links being pulled from the <span class="stt">h1</span> tag of each source file using <span class="RktSym"><a href="Template.html#%28def._%28%28lib._pollen%2Ftemplate..rkt%29._select%29%29" class="RktValLink" data-pltdoc="x">select</a></span>.</p></li></ul><h4>7.9<tt> </tt><a name="(part._.Third_tutorial_complete)"></a>Third tutorial complete</h4><p>OK, that was a humongous tutorial. Congratulations on making it through.</p><p>But your reward is that you now understand all the core concepts of the Pollen publishing system, including the most important ones: the flexibility of Pollen markup, and the connection between tags and functions.</p><p>Armed with this knowledge, you have everything you need to start doing useful things with Pollen. I hope you enjoy using it as much as I’ve enjoyed making it!</p><div class="navsetbottom"><span class="navleft"><div class="nosearchform"></div> </span><span class="navright"> <a href="second-tutorial.html" title="backward to "6 Second tutorial"" data-pltdoc="x">← prev</a> <a href="index.html" title="up to "Pollen: the book is a program"" data-pltdoc="x">up</a> <a href="raco-pollen.html" title="forward to "8 Using raco pollen"" data-pltdoc="x">next →</a></span> </div></div></div><div id="contextindicator"> </div></body></html> |