From 2f67c6a7ee0b254d497e0cd32feda21e73983342 Mon Sep 17 00:00:00 2001 From: Matthew Butterick Date: Thu, 22 Aug 2013 16:40:00 -0700 Subject: [PATCH] many improvements to regenerate --- command.rkt | 4 +- pollen-file-tools.rkt | 2 +- regenerate.rkt | 179 ++++++++++-------- server.rkt | 2 - template.rkt | 89 +++++++++ tests/-main.html | 1 - tests/-stain.html | 3 + tests/-stain.html.pp | 5 + tests/pollen-file-1.html | 3 + tests/{bibliography.p => pollen-file-1.p} | 2 + tests/pollen-file-2.html | 1 + tests/{pollen-lang-test.p => pollen-file-2.p} | 0 tests/subdir/in-a-subdir.p | 3 - tests/subtest/test.p | 3 - tests/test-pollen.html | 1 + tests/test.pmap | 27 +-- tests/test.txt | 1 - tests/test.txt.pp | 5 - tools.rkt | 53 ------ world.rkt | 5 +- 20 files changed, 216 insertions(+), 173 deletions(-) create mode 100644 template.rkt delete mode 100644 tests/-main.html create mode 100644 tests/-stain.html create mode 100644 tests/-stain.html.pp create mode 100644 tests/pollen-file-1.html rename tests/{bibliography.p => pollen-file-1.p} (99%) create mode 100644 tests/pollen-file-2.html rename tests/{pollen-lang-test.p => pollen-file-2.p} (100%) delete mode 100644 tests/subdir/in-a-subdir.p delete mode 100644 tests/subtest/test.p create mode 100644 tests/test-pollen.html delete mode 100644 tests/test.txt delete mode 100644 tests/test.txt.pp diff --git a/command.rkt b/command.rkt index 0e17ac0..89eb7c0 100644 --- a/command.rkt +++ b/command.rkt @@ -13,8 +13,8 @@ [("regenerate") `(begin ;; todo: take extensions off the comand line (displayln "Regenerate preproc & pmap files ...") - (require "regenerate.rkt" "pollen-file-tools.rkt") - (map force-regenerate (append-map project-files-with-ext (list POLLEN_PREPROC_EXT POLLEN_MAP_EXT))))] + (require "regenerate.rkt" "pollen-file-tools.rkt" "world.rkt") + (apply regenerate-with-session (append-map project-files-with-ext (list POLLEN_PREPROC_EXT POLLEN_MAP_EXT))))] [("clone") (let ([target-path (if (> (len args) 1) (->path (get args 1)) diff --git a/pollen-file-tools.rkt b/pollen-file-tools.rkt index ecbb9d1..323e7e9 100644 --- a/pollen-file-tools.rkt +++ b/pollen-file-tools.rkt @@ -165,6 +165,6 @@ (define/contract (project-files-with-ext ext) (symbol? . -> . (listof complete-path?)) - (filter (λ(i) (has-ext? i ext)) (directory-list pollen-file-root))) + (map ->complete-path (filter (λ(i) (has-ext? i ext)) (directory-list pollen-file-root)))) ;; todo: write tests for project-files-with-ext diff --git a/regenerate.rkt b/regenerate.rkt index c6b2321..77d8dfa 100644 --- a/regenerate.rkt +++ b/regenerate.rkt @@ -1,11 +1,11 @@ #lang racket/base (require racket/list racket/path racket/port racket/system - racket/file racket/rerequire racket/contract) -(require "world.rkt" "tools.rkt" "pmap.rkt" "readability.rkt") + racket/file racket/rerequire racket/contract racket/bool) +(require "world.rkt" "tools.rkt" "pmap.rkt" "readability.rkt" "template.rkt") (module+ test (require rackunit)) -(provide regenerate force-regenerate) +(provide regenerate regenerate-with-session) ;; mod-dates is a hash that takes lists of paths as keys, ;; and lists of modification times as values. @@ -74,87 +74,101 @@ ;; convenience function for external modules to use -(define/contract (force-regenerate x) - (pathish? . -> . void?) - (regenerate x #:force #t)) +(define/contract (regenerate-with-session . xs) + (() #:rest (listof pathish?) . ->* . void?) + ;; This will trigger regeneration of all files. + ;; Why not pass #:force #t through with regenerate? + ;; Because certain files will pass through multiple times (e.g., templates) + ;; And with #:force, they would be regenerated repeatedly. + ;; Using reset-mod-dates is sort of like session control: + ;; setting a state that persists through the whole operation. + (reset-mod-dates) + (for-each regenerate xs)) ;; dispatches path to the right regeneration function ;; use #:force to refresh regardless of cached state -(define/contract (regenerate x #:force [force #f]) - ((pathish?) (#:force boolean?) . ->* . void?) - (let ([path (->complete-path (->path x))]) - (cond - ;; this will catch pp (preprocessor) files - [(needs-preproc? path) (regenerate-with-preproc path #:force force)] - ;; this will catch p files, - ;; and files without extension that correspond to p files - [(needs-template? path) (regenerate-with-template path #:force force)] - ;; this will catch pmap (pollen map) files - [(pmap-source? path) (let ([pmap (dynamic-require path 'main)]) - (regenerate-with-pmap pmap #:force force))] - [(file-exists? path) (message "Regenerate: passing through" (->string (file-name-from-path path)))] - [else (error "File not found:" (->string (file-name-from-path path)))]))) +(define/contract (regenerate #:force [force #f] . xs) + (() (#:force boolean?) #:rest (listof pathish?) . ->* . void?) + (define (®enerate x) + (let ([path (->complete-path (->path x))]) + (cond + ;; this will catch pp (preprocessor) files + [(needs-preproc? path) (regenerate-with-preproc path #:force force)] + ;; this will catch p files, + ;; and files without extension that correspond to p files + [(needs-template? path) (regenerate-with-template path #:force force)] + ;; this will catch pmap (pollen map) files + [(pmap-source? path) (let ([pmap (dynamic-require path 'main)]) + (regenerate-with-pmap pmap #:force force))] + [(equal? FALLBACK_TEMPLATE_NAME (->string (file-name-from-path path))) + (message "Regenerate: using fallback template")] + [(file-exists? path) (message "Regenerate: passing through" (->string (file-name-from-path path)))] + [else (error "Regenerate couldn't find" (->string (file-name-from-path path)))]))) + (for-each ®enerate xs)) ;; todo: write tests -;; todo: write contract & tests -(define (regenerating-message path) +(define/contract (regenerating-message path) + (any/c . -> . void?) ;; you can actually stuff whatever string you want into path — ;; if it's not really a path, file-name-from-path won't choke (message "Regenerating:" (->string (file-name-from-path path)))) -;; todo: write contract & tests -(define (regenerated-message path) +(define/contract (regenerated-message path) + (any/c . -> . void?) (message "Regenerated:" (->string (file-name-from-path path)))) -;; todo: these are misnamed. Not "complete" -(define (complete-preproc-source-path x) - (define path (->path x)) - (if (preproc-source? path) - path - (make-preproc-source-path path))) +(define/contract (complete-preproc-source-path x) + (pathish? . -> . complete-path?) + (let ([path (->path x)]) + (->complete-path (if (preproc-source? path) + path + (make-preproc-source-path path))))) + +;; todo: tests + +(define/contract (complete-preproc-output-path x) + (pathish? . -> . complete-path?) + (let ([path (->path x)]) + (->complete-path (if (preproc-source? path) + (make-preproc-output-path path) + path)))) +;; todo: tests -(define (complete-preproc-output-path x) - (define path (->path x)) - (if (preproc-source? path) - (make-preproc-output-path path) - path)) (define/contract (regenerate-with-preproc x #:force [force #f]) (((and/c pathish? (flat-named-contract 'file-exists (λ(x) (file-exists? (complete-preproc-source-path x)))))) (#:force boolean?) . ->* . void?) - - ;; path might be either a preproc-source path or preproc-output path - ;; figure out which, then compute the other + ;; x might be either a preproc-source path or preproc-output path (define source-path (complete-preproc-source-path x)) (define output-path (complete-preproc-output-path x)) - ;; Three conditions under which we refresh: - (if (or - ;; 1) explicitly forced refresh - force - ;; 2) output file doesn't exist (so it definitely won't appear in mod-dates) - ;; also, this is convenient for development: - ;; you can trigger a refresh just by deleting the file - (not (file-exists? output-path)) - ;; 3) file otherwise needs refresh (e.g., it changed) - (mod-date-expired? source-path)) - ;; use single quotes to escape spaces in pathnames - (let ([command (format "~a '~a' > '~a'" RACKET_PATH source-path output-path)]) - (regenerating-message (format "~a from ~a" - (file-name-from-path output-path) - (file-name-from-path source-path))) - (store-refresh-in-mod-dates source-path) - ;; discard output using open-output-nowhere - (parameterize ([current-output-port (open-output-nowhere)]) - (system command)) - (regenerated-message output-path)) - ;; otherwise, skip file because there's no trigger for refresh - (message "File is up to date:" (->string (file-name-from-path output-path))))) + ;; Three conditions under which we refresh: + (if (or + ;; 1) explicitly forced refresh + force + ;; 2) output file doesn't exist (so it definitely won't appear in mod-dates) + ;; also, this is convenient for development: + ;; you can trigger a refresh just by deleting the file + (not (file-exists? output-path)) + ;; 3) file otherwise needs refresh (e.g., it changed) + (mod-date-expired? source-path)) + ;; use single quotes to escape spaces in pathnames + (let ([command (format "~a '~a' > '~a'" RACKET_PATH source-path output-path)]) + (regenerating-message (format "~a from ~a" + (file-name-from-path output-path) + (file-name-from-path source-path))) + (store-refresh-in-mod-dates source-path) + ;; discard output using open-output-nowhere + (parameterize ([current-output-port (open-output-nowhere)]) + (system command)) + (regenerated-message output-path)) + ;; otherwise, skip file because there's no trigger for refresh + (message "File is up to date:" (->string (file-name-from-path output-path))))) ;; todo: write tests @@ -207,21 +221,28 @@ ;; Then the rest: ;; set the template, regenerate the source file with template, and catch the output. - ;; 1) Set the template. + ;; 1) Set the template. (define template-path - (build-path source-dir - ;; if template name provided and exists, use that - (if (and template-name (file-exists? (build-path source-dir template-name))) - template-name - ;; Otherwise — try to get template name out of meta fields. - ;; todo: consider that template file in metas - ;; may not refer to a file that exists. - ;; what then? - (let ([source-metas (dynamic-require source-path 'metas)]) - (if (TEMPLATE_META_KEY . in? . source-metas) - (get source-metas TEMPLATE_META_KEY) - DEFAULT_TEMPLATE))))) - + (or + ;; Build the possible paths and use the first one + ;; that either exists, or has a preproc source that exists. + (ormap (λ(p) (if (ormap file-exists? (list p (make-preproc-source-path p))) p #f)) + (filter-not false? + (list + ;; path based on template-name + (and template-name (build-path source-dir template-name)) + ;; path based on metas + (let ([source-metas (dynamic-require source-path 'metas)]) + (and (TEMPLATE_META_KEY . in? . source-metas) + (build-path source-dir + (get source-metas TEMPLATE_META_KEY)))) + ;; path using default template name + (build-path source-dir DEFAULT_TEMPLATE)))) + ;; if none of these work, make temporary template file + (let ([tp (build-path source-dir FALLBACK_TEMPLATE_NAME)]) + (display-to-file #:exists 'replace fallback-template-data tp) + tp))) + ;; refresh template (it might have its own preprocessor file) (regenerate template-path #:force force) @@ -242,7 +263,11 @@ (let ([page-result (render-source-with-template source-path template-path)]) (display-to-file #:exists 'replace page-result output-path) (regenerated-message (file-name-from-path output-path)))) - (message "File is up to date:" (->string (file-name-from-path output-path))))) + (message "Regenerate with template: file is up to date:" (->string (file-name-from-path output-path)))) + + ;; delete fallback template if needed + (let ([tp (build-path source-dir FALLBACK_TEMPLATE_NAME)]) + (when (file-exists? tp) (delete-file tp)))) (define/contract (render-source-with-template source-path template-path) @@ -272,8 +297,10 @@ ;; regenerate files listed in a pmap file (define/contract (regenerate-with-pmap pmap #:force [force #f]) - (pmap? . -> . void?) + ((pmap?) (#:force boolean?) . ->* . void?) ;; pass force parameter through (for-each (λ(i) (regenerate i #:force force)) (all-pages pmap))) + + ;; todo: write test diff --git a/server.rkt b/server.rkt index ab50677..7400757 100755 --- a/server.rkt +++ b/server.rkt @@ -6,8 +6,6 @@ (displayln "Pollen server starting...") -(define pollen-file-root (current-directory)) - (define/contract (route-wrapper route-proc) ;; todo: make better contract for return value ((complete-path? . -> . tagged-xexpr?) . -> . procedure?) diff --git a/template.rkt b/template.rkt new file mode 100644 index 0000000..9c40050 --- /dev/null +++ b/template.rkt @@ -0,0 +1,89 @@ +#lang racket/base +(require racket/list racket/string xml xml/path) +(require "readability.rkt" "debug.rkt" "predicates.rkt" "tools.rkt") + +;; setup for test cases +(module+ test (require rackunit)) + +(provide (all-defined-out)) + +;; todo: better fallback template + +(define fallback-template-data "FALLBACK! ◊(put-as-html main)") + +;; todo: tests & contracts for this subsection + +(define (from x query) + ; cache x + (let ([x (put x)]) + ; try finding it in metas, if not, find it in main, if not then return false + (or (from-metas x query) (from-main x query)))) + +(define (from-main x query) ; this used to be plain from + ; check results first + (let* ([x (put x)] + [results (se-path*/list (list query) x)]) + ; if results exist, send back xexpr as output + (if (not (empty? results)) + `(,query ,@results) ; todo: why use query as tag? + #f))) + +(define (from-metas x key) + (let* ([x (put x)] + [meta-hash (make-meta-hash x)] + [key (->symbol key)]) + (if (in? meta-hash key) + `(value ,(get meta-hash key)) ;todo: why use value as tag? + #f))) + +(define (put x) + ; handles either xexpr or pollen file as input + (cond + ; pass through xexpr as is + ; put is optional for xexprs. + ; it's only here to make the idiom smooth. + [(tagged-xexpr? x) x] + ; todo: how to externalize pollen main tag into world name? + [(file-exists? (->path x)) (dynamic-require x 'main)] + ; also try adding pollen file extension + ; this makes put compatible with map references + [(let ([x (make-pollen-source-path x)]) + (when (file-exists? x) + (put x)))] + [else (error "put: need named xexpr or pollen file, but got" x)])) + + +(define (merge x) + (cond + [(tagged-xexpr? x) + ; return content of xexpr. + ; pollen language rules will splice these into the main flow. + (if (empty? x) + "" + (let-values([(name attr content) (break-tagged-xexpr x)]) + content))] + [(string? x) (list x)])) + + +#|(define (merge-strings x) + (when (empty? x) (error "merge-strings got empty x")) + ;todo: filter metas? + ; leaning toward no. Simplest behavior. + ; function is not intended to be used with whole pollen body anyhow. + (let ([x (merge x)]) + (string-join (filter string? (flatten x)) " ")))|# + +(define (merge-strings x) + (string-join (filter string? (flatten x)) " ")) + + +(define (make-html x) + (if (tagged-xexpr? x) + (xexpr->string x) + (let ([x (->list x)]) + (when (andmap xexpr? x) + (string-join (map xexpr->string x) ""))))) + +; generate *-as-html versions of functions +(define-values (put-as-html merge-as-html merge-strings-as-html) + (apply values (map (λ(proc) (λ(x) (make-html (proc x)))) (list put merge merge-strings)))) diff --git a/tests/-main.html b/tests/-main.html deleted file mode 100644 index e9633fd..0000000 --- a/tests/-main.html +++ /dev/null @@ -1 +0,0 @@ -◊(put-as-html main) \ No newline at end of file diff --git a/tests/-stain.html b/tests/-stain.html new file mode 100644 index 0000000..5ac9228 --- /dev/null +++ b/tests/-stain.html @@ -0,0 +1,3 @@ +OH JOY + +◊(put-as-html main) \ No newline at end of file diff --git a/tests/-stain.html.pp b/tests/-stain.html.pp new file mode 100644 index 0000000..9b3df2f --- /dev/null +++ b/tests/-stain.html.pp @@ -0,0 +1,5 @@ +#lang planet mb/pollen/pre + +OH JOY + +◊"◊"(put-as-html main) \ No newline at end of file diff --git a/tests/pollen-file-1.html b/tests/pollen-file-1.html new file mode 100644 index 0000000..dad25c8 --- /dev/null +++ b/tests/pollen-file-1.html @@ -0,0 +1,3 @@ +OH JOY + +put-as-htmlroot-functionptopicclasssmallBibliographyplcThis is not, by any measure, a comprehensive bibliography. Rather, it’s a selection of favorites from my own bookshelf that I consult most frequently in my work as a writer and a typographer.psubheadwritingpBryan A. Garner, bookGarner’s Modern American Usage, 3rd ed. (New York: Oxford University Press, 2009).pindentedstyleposition:relative;top:-0.4emLong before he agreed to write the foreword for my book bookTypography for Lawyers, Bryan Garner was a hero of mine. Garner thinks and writes about American English in a way that’s rigorous, convincing, and accessible. He is stern but not shrill; authoritative but not authoritarian. He is a vigorous advocate for clear, simple writing. His work should be mandatory reading for all writers.psubheadTypographypMatthew Butterick, bookTypography for Lawyers (Houston: Jones McClure Publishing, 2010).pindentedstyleposition:relative;top:-0.4emThe precursor to bookButterick’s Practical Typography. Lawyer or not, consider buying a copy, because it’s a virtuous act. See xrefhow to pay for this book.pJan Middendorp, bookShaping Text (Amsterdam: BIS Publishers, 2012).pindentedstyleposition:relative;top:-0.4emIf you get a second book on typography, get this one. Middendorp’s beautifully written and illustrated book is full of careful details and lucid explanations.pCarolina de Bartolo, bookExplorations in Typography (slinkexplorationsintypography.comhttp://explorationsintypography.com, 2011).pindentedstyleposition:relative;top:-0.4emUsing a Spiekermann essay from bookStop Stealing Sheep (see below), de Bartolo shows how different typesetting choices change the effect of the text.pCyrus Highsmith, bookInside Paragraphs (Boston: Font Bureau, 2012).pindentedstyleposition:relative;top:-0.4emHighsmith’s charmingly hand-illustrated book focuses on the paragraph as a unit of typographic interest.pRobert Bringhurst, bookThe Elements of Typographic Style, 3rd ed. (Vancouver: Hartley and Marks Publishers, 2004).pindentedstyleposition:relative;top:-0.4emBringhurst’s book has become something of a standard reference guide among professional typographers, bringing together the history, theory, and practice of typography.pEllen Lupton, bookThinking With Type, 2nd ed. (New York: Princeton Architectural Press, 2010).pindentedstyleposition:relative;top:-0.4emIntended as an introduction to typography for design students, Lupton’s book is more accessible than Bringhurst’s. It includes full-color illustrations from every era of typography.psubheadFontspErik Spiekermann and E. M. Ginger, bookStop Stealing Sheep & Find Out How Type Works, 2nd ed. (Berkeley, California: Adobe Press, 2002).pindentedstyleposition:relative;top:-0.4emGinger & Spiekermann, a self-described typomaniac (and author of the xrefforeword) explain how fonts work, and how they differ in appearance and in function. My font xrefHermes is among those featured.pStephen Coles, bookThe Anatomy of Type (London: Quid Publishing Ltd., 2012).pindentedstyleposition:relative;top:-0.4emExplores the major categories of fonts and their characteristic qualities by examining 100 fonts in detail.psubheadDesign principlespEdward Tufte, bookEnvisioning Information, 4th printing ed. (Cheshire, Connecticut: Graphics Press, 1990).pEdward Tufte, bookThe Visual Display of Quantitative Information, 2nd ed. (Cheshire, Connecticut: Graphics Press, 2001).pindentedstyleposition:relative;top:-0.4emThese are two of my favorite books of all time. Tufte makes an eloquent and compelling case for why design matters. Both books are fantastically interesting and beautifully illustrated with examples of information design from many historical periods.pWilliam Lidwell, Kritina Holden, and Jill Butler, bookUniversal Principles of Design, 2nd ed. (Beverly, Massachusetts: Rockport Publishers, 2010).pindentedstyleposition:relative;top:-0.4emAn excellent and accessible introduction to design principles that apply not only to printed documents, but to all objects that we interact with. \ No newline at end of file diff --git a/tests/bibliography.p b/tests/pollen-file-1.p similarity index 99% rename from tests/bibliography.p rename to tests/pollen-file-1.p index 6b41768..35ab436 100644 --- a/tests/bibliography.p +++ b/tests/pollen-file-1.p @@ -1,5 +1,7 @@ #lang planet mb/pollen +◊meta["template" "-stain.html"] + ◊topic['((class "small"))]{Bibliography} ◊lc{T}his is not, by any measure, a comprehensive bibliography. Rather, it’s a selection of favorites from my own bookshelf that I consult most frequently in my work as a writer and a typographer. diff --git a/tests/pollen-file-2.html b/tests/pollen-file-2.html new file mode 100644 index 0000000..d88909a --- /dev/null +++ b/tests/pollen-file-2.html @@ -0,0 +1 @@ +FALLBACK! put-as-htmlroot-functionpdquo“Hello” world, aren’t you—yes, you—about 1–2 inches tall?bloqIn a blockpWefooblesquo‘Love’pGoodnightbrmoonpbar \ No newline at end of file diff --git a/tests/pollen-lang-test.p b/tests/pollen-file-2.p similarity index 100% rename from tests/pollen-lang-test.p rename to tests/pollen-file-2.p diff --git a/tests/subdir/in-a-subdir.p b/tests/subdir/in-a-subdir.p deleted file mode 100644 index 64a9dff..0000000 --- a/tests/subdir/in-a-subdir.p +++ /dev/null @@ -1,3 +0,0 @@ -#lang planet mb/pollen - -I'm in a subdirectory. \ No newline at end of file diff --git a/tests/subtest/test.p b/tests/subtest/test.p deleted file mode 100644 index a95b37d..0000000 --- a/tests/subtest/test.p +++ /dev/null @@ -1,3 +0,0 @@ -#lang planet mb/pollen - -This is a test of the regen system. \ No newline at end of file diff --git a/tests/test-pollen.html b/tests/test-pollen.html new file mode 100644 index 0000000..5f43fcb --- /dev/null +++ b/tests/test-pollen.html @@ -0,0 +1 @@ +

Bibliography

This is not, by any measure, a comprehensive bibliography. Rather, it’s a selection of favorites from my own bookshelf that I consult most frequently in my work as a writer and a typographer.

writing

Bryan A. Garner, Garner’s Modern American Usage, 3rd ed. (New York: Oxford University Press, 2009).

Long before he agreed to write the foreword for my book Typography for Lawyers, Bryan Garner was a hero of mine. Garner thinks and writes about American English in a way that’s rigorous, convincing, and accessible. He is stern but not shrill; authoritative but not authoritarian. He is a vigorous advocate for clear, simple writing. His work should be mandatory reading for all writers.

Typography

Matthew Butterick, Typography for Lawyers (Houston: Jones McClure Publishing, 2010).

The precursor to Butterick’s Practical Typography. Lawyer or not, consider buying a copy, because it’s a virtuous act. See how to pay for this book.

Jan Middendorp, Shaping Text (Amsterdam: BIS Publishers, 2012).

If you get a second book on typography, get this one. Middendorp’s beautifully written and illustrated book is full of careful details and lucid explanations.

Carolina de Bartolo, Explorations in Typography (explorationsintypography.comhttp://explorationsintypography.com, 2011).

Using a Spiekermann essay from Stop Stealing Sheep (see below), de Bartolo shows how different typesetting choices change the effect of the text.

Cyrus Highsmith, Inside Paragraphs (Boston: Font Bureau, 2012).

Highsmith’s charmingly hand-illustrated book focuses on the paragraph as a unit of typographic interest.

Robert Bringhurst, The Elements of Typographic Style, 3rd ed. (Vancouver: Hartley and Marks Publishers, 2004).

Bringhurst’s book has become something of a standard reference guide among professional typographers, bringing together the history, theory, and practice of typography.

Ellen Lupton, Thinking With Type, 2nd ed. (New York: Princeton Architectural Press, 2010).

Intended as an introduction to typography for design students, Lupton’s book is more accessible than Bringhurst’s. It includes full-color illustrations from every era of typography.

Fonts

Erik Spiekermann and E. M. Ginger, Stop Stealing Sheep & Find Out How Type Works, 2nd ed. (Berkeley, California: Adobe Press, 2002).

Ginger & Spiekermann, a self-described typomaniac (and author of the foreword) explain how fonts work, and how they differ in appearance and in function. My font Hermes is among those featured.

Stephen Coles, The Anatomy of Type (London: Quid Publishing Ltd., 2012).

Explores the major categories of fonts and their characteristic qualities by examining 100 fonts in detail.

Design principles

Edward Tufte, Envisioning Information, 4th printing ed. (Cheshire, Connecticut: Graphics Press, 1990).

Edward Tufte, The Visual Display of Quantitative Information, 2nd ed. (Cheshire, Connecticut: Graphics Press, 2001).

These are two of my favorite books of all time. Tufte makes an eloquent and compelling case for why design matters. Both books are fantastically interesting and beautifully illustrated with examples of information design from many historical periods.

William Lidwell, Kritina Holden, and Jill Butler, Universal Principles of Design, 2nd ed. (Beverly, Massachusetts: Rockport Publishers, 2010).

An excellent and accessible introduction to design principles that apply not only to printed documents, but to all objects that we interact with.

\ No newline at end of file diff --git a/tests/test.pmap b/tests/test.pmap index 823e99e..d0bab05 100644 --- a/tests/test.pmap +++ b/tests/test.pmap @@ -1,26 +1,5 @@ #lang planet mb/pollen -index -typography-in-ten-minutes -summary-of-key-rules -foreword -introduction -how-to-use -how-to-pay-for-this-book -◊why-typography-matters{ - what-is-typography - where-do-the-rules-come-from} -◊type-composition{ - straight-and-curly-quotes - one-space-between-sentences - trademark-and-copyright-symbols - ligatures} -◊appendix{ - printers-and-paper - how-to-make-a-pdf - typewriter-habits - common-accented-characters - identifying-fonts - bibliography - charter - mb-lectures-and-articles} + +pollen-file-1 +pollen-file-2 \ No newline at end of file diff --git a/tests/test.txt b/tests/test.txt deleted file mode 100644 index 8bd19c6..0000000 --- a/tests/test.txt +++ /dev/null @@ -1 +0,0 @@ -This will print bar: bar \ No newline at end of file diff --git a/tests/test.txt.pp b/tests/test.txt.pp deleted file mode 100644 index 6606cdb..0000000 --- a/tests/test.txt.pp +++ /dev/null @@ -1,5 +0,0 @@ -#lang planet mb/pollen/pre - -◊(define foo "bar") - -This will print bar: ◊foo \ No newline at end of file diff --git a/tools.rkt b/tools.rkt index 3e8b2a4..2d664ce 100644 --- a/tools.rkt +++ b/tools.rkt @@ -216,56 +216,3 @@ (hash "foo" "haw"))) -;; todo: tests & contracts for this subsection - -(define (put x) - ; handles either xexpr or pollen file as input - (cond - ; pass through xexpr as is - ; put is optional for xexprs. - ; it's only here to make the idiom smooth. - [(tagged-xexpr? x) x] - ; todo: how to externalize pollen main tag into world name? - [(file-exists? (->path x)) (dynamic-require x 'main)] - ; also try adding pollen file extension - ; this makes put compatible with map references - [(let ([x (make-pollen-source-path x)]) - (when (file-exists? x) - (put x)))] - [else (error "put: need named xexpr or pollen file, but got" x)])) - - -(define (merge x) - (cond - [(tagged-xexpr? x) - ; return content of xexpr. - ; pollen language rules will splice these into the main flow. - (if (empty? x) - "" - (let-values([(name attr content) (break-tagged-xexpr x)]) - content))] - [(string? x) (list x)])) - - -#|(define (merge-strings x) - (when (empty? x) (error "merge-strings got empty x")) - ;todo: filter metas? - ; leaning toward no. Simplest behavior. - ; function is not intended to be used with whole pollen body anyhow. - (let ([x (merge x)]) - (string-join (filter string? (flatten x)) " ")))|# - -(define (merge-strings x) - (string-join (filter string? (flatten x)) " ")) - - -(define (make-html x) - (if (tagged-xexpr? x) - (xexpr->string x) - (let ([x (->list x)]) - (when (andmap xexpr? x) - (string-join (map xexpr->string x) ""))))) - -; generate *-as-html versions of functions -(define-values (put-as-html merge-as-html merge-strings-as-html) - (apply values (map (λ(proc) (λ(x) (make-html (proc x)))) (list put merge merge-strings)))) diff --git a/world.rkt b/world.rkt index 92ca9ed..a86130d 100644 --- a/world.rkt +++ b/world.rkt @@ -7,13 +7,14 @@ (define TEMPLATE_FIELD_DELIMITER POLLEN_EXPRESSION_DELIMITER) (define DEFAULT_TEMPLATE "-main.html") -(define TEMPLATE_META_KEY 'template) +(define FALLBACK_TEMPLATE_NAME "-temp-fallback-template.html") +(define TEMPLATE_META_KEY "template") (define POLLEN_MAP_EXT 'pmap) (define DEFAULT_POLLEN_MAP "main.pmap") (define POLLEN_MAP_PARENT_KEY 'parent) -(define MAIN_POLLEN_EXPORT 'body) +(define MAIN_POLLEN_EXPORT 'main) ;(define META_POLLEN_TAG 'metas) ;(define META_POLLEN_EXPORT 'metas)