diff --git a/pollen-lp-test.rkt b/pollen-lp-test.rkt index f458f56..e4fbaf6 100644 --- a/pollen-lp-test.rkt +++ b/pollen-lp-test.rkt @@ -167,4 +167,42 @@ will be combined into a single submodule. (check-txexprs-equal? ◊section{foo} '(h2 ((class "section")) "foo")) (check-txexprs-equal? ◊chapter{foo} - '(h1 ((class "chapter")) "foo"))) \ No newline at end of file + '(h1 ((class "chapter")) "foo"))) + +(module+ test + (let ([my-fake-metas (hash 'title "Fake Title" 'white "noise")]) + (check-txexprs-equal? ◊topic-from-metas[my-fake-metas] + '(h3 ((class "topic")) "Fake Title")) + (check-txexprs-equal? ◊section-from-metas[my-fake-metas] + '(h2 ((class "section")) "Fake Title")) + (check-txexprs-equal? ◊chapter-from-metas[my-fake-metas] + '(h1 ((class "chapter")) "Fake Title")))) + +(module+ test + (check-txexprs-equal? ◊hanging-topic["Topic name"]{One-line explanation} + `(div ((class "hanging-topic") ,no-hyphens-attr) "Topic name" + (p (,no-hyphens-attr) "One-line explanation")))) + +(module+ test + (check-txexprs-equal? + ◊(quick-table "heading-one | heading-two" "\n" + " three | four" "\n" + "five | six ") + '(table (tr (th "heading-one") (th "heading-two")) + (tr (td "three") (td "four")) + (tr (td "five") (td "six"))))) + +(module+ test + (check-txexprs-equal? (hyphenate-block `(div "snowman" (span (,no-hyphens-attr) "snowman"))) + `(div "snow\u00ADman" (span (,no-hyphens-attr) "snowman")))) + +(module+ test + (check-txexprs-equal? (make-quotes-hangable "“Who is it?”") + '(quo "" (dquo-push) (dquo-pull "“") "Who is it?”"))) + +(module+ test + (check-equal? (fix-em-dashes "Hey — you!") "Hey—you!") + (check-equal? (fix-em-dashes "Hey—you!") "Hey—you!")) + +(module+ test + (check-equal? (capitalize-first-letter "foo dog") "Foo dog")) \ No newline at end of file diff --git a/pollen-lp.scrbl b/pollen-lp.scrbl index d09f3ef..0526c97 100644 --- a/pollen-lp.scrbl +++ b/pollen-lp.scrbl @@ -21,33 +21,7 @@ file and see how they affect the output. We could avoid the next @racket[require] if we were using @|lang| @racketmodname[racket], because these libraries would already be available. -@chunk[<*> - - - - - - - - - - - - - - - - - - - - - url> - - - - - ] + @chunk[ (require @@ -670,40 +644,40 @@ Macro for defining a function that makes a heading by relying on data in the met #'(define (heading-from-metas metas) (heading-name (hash-ref metas meta-key-for-page-title))))]))] -@;|{ - - (define-heading-from-metas topic) +@deftogether[( +@defproc[ +(topic-from-metas [metas hash?]) +txexpr?] +@defproc[ +(section-from-metas [metas hash?]) +txexpr?] +@defproc[ +(chapter-from-metas [metas hash?]) +txexpr?])] + + @chunk[ + (define-heading-from-metas topic) (define-heading-from-metas section) - (define-heading-from-metas chapter) - - (module+ test - (let ([my-fake-metas (hash 'title "Fake Title" 'white "noise")]) - (check-txexprs-equal? ◊topic-from-metas[my-fake-metas] - '(h3 ((class "topic")) "Fake Title")) - (check-txexprs-equal? ◊section-from-metas[my-fake-metas] - '(h2 ((class "section")) "Fake Title")) - (check-txexprs-equal? ◊chapter-from-metas[my-fake-metas] - '(h1 ((class "chapter")) "Fake Title")))) - - #| - @racket[hanging-topic]: convert a topic + subhead into one HTML markup unit - - ◊hanging-topic["Topic name"]{One-line explanation} + (define-heading-from-metas chapter)] + +@defproc[ +(hanging-topic +[topic-xexpr xexpr?] +[pollen-args (listof xexpr?)] ...) +txexpr?] +Convert a topic + subhead into one HTML markup unit - |# - (define (hanging-topic topic-xexpr . text-args) +@chunk[ + (define (hanging-topic topic-xexpr . pollen-args) (txexpr 'div (list '(class "hanging-topic") no-hyphens-attr) - (list topic-xexpr (list* 'p (list no-hyphens-attr) text-args)))) - - (module+ test - (check-txexprs-equal? ◊hanging-topic["Topic name"]{One-line explanation} - `(div ((class "hanging-topic") ,no-hyphens-attr) "Topic name" - (p (,no-hyphens-attr) "One-line explanation")))) - - - #| - @racket[quick-table]: make little HTML tables with simplified notation + (list topic-xexpr (list* 'p (list no-hyphens-attr) pollen-args))))] + +@defproc[ +(quick-table +[table-rows (listof xexpr?)] ...) +txexpr?] +Make an HTML table using simplified notation ◊quick-table{heading left | heading center | heading right upper left | upper center | upper right @@ -719,9 +693,9 @@ Macro for defining a function that makes a heading by relying on data in the met This function assumes that each row has the same number of columns. You could improve it to fill in blank cells in rows that need them. - - |# - + + +@chunk[ (define (quick-table . text-args) ;; In Pollen, a multiline text-args block arrives as a list of lines and linebreak characters. @@ -757,20 +731,14 @@ Macro for defining a function that makes a heading by relying on data in the met ;; Converts an expression of the form @racket[(apply func (list arg1 arg2 ...))] ;; Into @racket[(func arg1 arg2 ...)] (cons 'table (for/list ([html-row (in-list html-rows)]) - (apply tr-tag html-row)))) - - (module+ test - (check-txexprs-equal? - ◊(quick-table "heading-one | heading-two" "\n" - " three | four" "\n" - "five | six ") - '(table (tr (th "heading-one") (th "heading-two")) - (tr (td "three") (td "four")) - (tr (td "five") (td "six"))))) - - #| - @racket[pdf-thumbnail-link]: create a thumbnail of a PDF that links to the PDF - + (apply tr-tag html-row))))] + +@defproc[ +(pdf-thumbnail +[pdf-path path-string?]) +txexpr?] +Create a thumbnail of a PDF that links to the PDF. + This function will only work properly if you have @racket[sips] on your system (command-line image-processing program, included with OS X). @@ -780,24 +748,37 @@ Macro for defining a function that makes a heading by relying on data in the met One disadvantage of this approach is that the thumbnail will *always* be generated on recompile, though you could put in some logic to avoid this (e.g., check the modification date of the PDF). In this case, @racket[sips] is fast enough that it's not bothersome. - - |# - (define (pdf-thumbnail-link pdf-pathstring) + + @chunk[ + (define (pdf-thumbnail-link pdf-pathstring) (define img-extension "gif") (define img-pathstring (->string (add-ext (remove-ext pdf-pathstring) img-extension))) (define sips-command (format "sips -Z 2000 -s format ~a --out '~a' '~a' > /dev/null" img-extension img-pathstring pdf-pathstring)) - ◊link[pdf-pathstring]{◊(if (system sips-command) + (link pdf-pathstring (if (system sips-command) `(img ((src ,img-pathstring))) ;; usually one would raise an error on the next line, ;; but for instructional purposes, we'll have a graceful fail - "sips not available")}) - - - #| - A few convenience variants of @racket[pdf-thumbnail-link] - |# + "sips not available")))] + +@deftogether[( +@defproc[ +(pdf-thumbnail-link-from-metas +[metas hash?]) +txexpr?] +@defproc[ +(before-and-after-pdfs +[base-name string?]) +txexpr?] +@defproc[ +(alternate-after-pdf +[base-name string?]) +txexpr?] +)] +A few convenience variants of @racket[pdf-thumbnail-link] + + @chunk[ (define (pdf-thumbnail-link-from-metas metas) (define-values (dir fn _) (split-path (add-ext (remove-ext* (hash-ref metas 'here-path)) "pdf"))) (pdf-thumbnail-link (->string fn))) @@ -814,11 +795,13 @@ Macro for defining a function that makes a heading by relying on data in the met (define (alternate-after-pdf base-name) `(div ((class "pdf-thumbnail")) "after (alternate)" (br) - ,(pdf-thumbnail-link (format "pdf/sample-doc-~a-after-alternate.pdf" base-name)))) - - - #| - @racket[root]: decode page content + ,(pdf-thumbnail-link (format "pdf/sample-doc-~a-after-alternate.pdf" base-name))))] + +@defproc[ +(root +[pollen-args (listof txexpr?)] ...) +txexpr?] +Decode page content In a Pollen markup source, the output is a tagged X-expression that starts with @racket[root]: @@ -833,8 +816,8 @@ Macro for defining a function that makes a heading by relying on data in the met Often, you'll want to use a @racket[decode] function, which can recursively perform different kinds of processing on different types of page elements. - - |# + +@chunk[ (define (root . elems) ;; We will do the decoding in two steps. ;; Detect paragraphs first so that they're treated as block-txexprs in next phase. @@ -846,11 +829,15 @@ Macro for defining a function that makes a heading by relying on data in the met #:string-proc (compose1 make-quotes-hangable fix-em-dashes smart-quotes) - #:exclude-tags '(style script)))) - - #| - @racket[hyphenate-block]: helper function for root decoder - |# + #:exclude-tags '(style script))))] + +@defproc[ +(hyphenate-block +[block-tx txexpr?]) +txexpr?] +Helper function for root decoder + +@chunk[ (define (hyphenate-block block-tx) ;; The basic @racket[hyphenate] function comes from the @racket[hyphenate] module. ;; We could attach @racket[hyphenate] to our decoder as a string processor rather than block processor. @@ -862,21 +849,21 @@ Macro for defining a function that makes a heading by relying on data in the met (hyphenate block-tx #:min-left-length 3 #:min-right-length 3 - #:omit-txexpr no-hyphens?)) - - (module+ test - (check-txexprs-equal? (hyphenate-block `(div "snowman" (span (,no-hyphens-attr) "snowman"))) - `(div "snow\u00ADman" (span (,no-hyphens-attr) "snowman")))) - - #| - @racket[make-quotes-hangable]: perform tricky processing on quotation marks. + #:omit-txexpr no-hyphens?))] + +@defproc[ +(make-quotes-hangable +[str string?]) +txexpr?] +Perform tricky processing on quotation marks. Because I'm a typography snob I like to push quotation marks into the margin a little bit when they appear at the left edge of a line (aka "hanging quotes"). This function just wraps left-hand quote marks in two little tags ("push" and "pull") that I can then manipulate in CSS to get the effect. - |# + +@chunk[ (define (make-quotes-hangable str) ;; using @racket[regexp-match*] with #:gap-select? makes it act like a funny kind of string splitter (define substrs (regexp-match* #px"\\s?[“‘]" str #:gap-select? #t)) @@ -889,41 +876,39 @@ Macro for defining a function that makes a heading by relying on data in the met [("‘") (list '(squo-push) `(squo-pull ,str))] [("“") (list '(dquo-push) `(dquo-pull ,str))] [else (list str)]) - (list str)))) substrs)))) - - (module+ test - (check-txexprs-equal? (make-quotes-hangable "“Who is it?”") - '(quo "" (dquo-push) (dquo-pull "“") "Who is it?”"))) - - #| - @racket[fix-em-dashes]: helper function for root decoder + (list str)))) substrs))))] + +@defproc[ +(fix-em-dashes +[str string?]) +txexpr?] +Helper function for root decoder When I type an em dash in my sources, I will often leave a space around it, but I don't want spaces in the output, so this function removes them. - |# - (define (fix-em-dashes str) + + @chunk[ + (define (fix-em-dashes str) ;; \u00A0 = nbsp, \u2009 = thinsp (neither included in \s) (let* ([str (regexp-replace* #px"(?<=\\w)[\u00A0\u2009\\s]—" str "—")] [str (regexp-replace* #px"—[\u00A0\u2009\\s](?=\\w)" str "—")]) - str)) - - (module+ test - (check-equal? (fix-em-dashes "Hey — you!") "Hey—you!") - (check-equal? (fix-em-dashes "Hey—you!") "Hey—you!")) - - #| - @racket[capitalize-first-letter]: utility function for use in HTML templates. - |# + str))] + +@defproc[ +(capitalize-first-letter +[str string?]) +string?] +utility function for use in HTML templates. + + @chunk[ (define (capitalize-first-letter str) - (regexp-replace #rx"^." str string-upcase)) - - (module+ test - (check-equal? (capitalize-first-letter "foo dog") "Foo dog")) - - - #| - Miscellaneous tag functions. Obvious at this point what they do. - |# + (regexp-replace #rx"^." str string-upcase))] + + @subsubsection{Miscellaneous tag functions} + + Presented without docs or comment, as it should be obvious at this point what they do. + +@chunk[ (define omission (make-default-tag-function 'div #:class "omission")) (define mono (make-default-tag-function 'span #:class "mono")) @@ -953,6 +938,51 @@ Macro for defining a function that makes a heading by relying on data in the met (define (captioned name . xs) `(table ((class "captioned indented")) - (tr (td ((style "text-align:left")) ,@xs) (td ,(caption name))))) + (tr (td ((style "text-align:left")) ,@xs) (td ,(caption name)))))] + +@;|{ + #| + |# + - }| \ No newline at end of file + }| + + + @chunk[<*> + + + + + + + + + + + + + + + + + + + + + url> + + + + + + + + + + + + + + + + ] \ No newline at end of file diff --git a/pollen.rkt b/pollen.rkt index 1c6e71e..aec82b2 100644 --- a/pollen.rkt +++ b/pollen.rkt @@ -623,14 +623,7 @@ For fun, I used Pollen notation inside the macro just to show you that it will w (define-heading-from-metas section) (define-heading-from-metas chapter) -(module+ test - (let ([my-fake-metas (hash 'title "Fake Title" 'white "noise")]) - (check-txexprs-equal? ◊topic-from-metas[my-fake-metas] - '(h3 ((class "topic")) "Fake Title")) - (check-txexprs-equal? ◊section-from-metas[my-fake-metas] - '(h2 ((class "section")) "Fake Title")) - (check-txexprs-equal? ◊chapter-from-metas[my-fake-metas] - '(h1 ((class "chapter")) "Fake Title")))) + #| `hanging-topic`: convert a topic + subhead into one HTML markup unit @@ -642,10 +635,7 @@ For fun, I used Pollen notation inside the macro just to show you that it will w (make-txexpr 'div (list '(class "hanging-topic") no-hyphens-attr) (list topic-xexpr (list* 'p (list no-hyphens-attr) text-args)))) -(module+ test - (check-txexprs-equal? ◊hanging-topic["Topic name"]{One-line explanation} - `(div ((class "hanging-topic") ,no-hyphens-attr) "Topic name" - (p (,no-hyphens-attr) "One-line explanation")))) + #| @@ -705,14 +695,7 @@ You could improve it to fill in blank cells in rows that need them. (cons 'table (for/list ([html-row (in-list html-rows)]) (apply tr-tag html-row)))) -(module+ test - (check-txexprs-equal? - ◊(quick-table "heading-one | heading-two" "\n" - " three | four" "\n" - "five | six ") - '(table (tr (th "heading-one") (th "heading-two")) - (tr (td "three") (td "four")) - (tr (td "five") (td "six"))))) + #| `pdf-thumbnail-link`: create a thumbnail of a PDF that links to the PDF @@ -810,9 +793,7 @@ processing on different types of page elements. #:min-right-length 3 #:omit-txexpr no-hyphens?)) -(module+ test - (check-txexprs-equal? (hyphenate-block `(div "snowman" (span (,no-hyphens-attr) "snowman"))) - `(div "snow\u00ADman" (span (,no-hyphens-attr) "snowman")))) + #| `make-quotes-hangable`: perform tricky processing on quotation marks. @@ -837,9 +818,7 @@ that I can then manipulate in CSS to get the effect. [else (list str)]) (list str)))) substrs)))) -(module+ test - (check-txexprs-equal? (make-quotes-hangable "“Who is it?”") - '(quo "" (dquo-push) (dquo-pull "“") "Who is it?”"))) + #| `fix-em-dashes`: helper function for root decoder @@ -853,9 +832,7 @@ but I don't want spaces in the output, so this function removes them. [str (regexp-replace* #px"—[\u00A0\u2009\\s](?=\\w)" str "—")]) str)) -(module+ test - (check-equal? (fix-em-dashes "Hey — you!") "Hey—you!") - (check-equal? (fix-em-dashes "Hey—you!") "Hey—you!")) + #| `capitalize-first-letter`: utility function for use in HTML templates. @@ -863,8 +840,7 @@ but I don't want spaces in the output, so this function removes them. (define (capitalize-first-letter str) (regexp-replace #rx"^." str string-upcase)) -(module+ test - (check-equal? (capitalize-first-letter "foo dog") "Foo dog")) + #|