From 7c9cac4e3abe60dcf06c6248b3d70601b1ea8d94 Mon Sep 17 00:00:00 2001 From: Matthew Butterick Date: Wed, 21 Aug 2013 23:22:18 -0700 Subject: [PATCH] improvements to regenerate --- main.rkt | 4 ++- regenerate.rkt | 68 +++++++++++++++++++++++++---------------- tests/bibliography.html | 2 +- tests/subtest/test.p | 3 ++ tests/test-requirer.p | 12 -------- tools.rkt | 56 ++++++++++++++++++++++++++++++++- 6 files changed, 104 insertions(+), 41 deletions(-) create mode 100644 tests/subtest/test.p diff --git a/main.rkt b/main.rkt index c9b97c7..b2c21bd 100644 --- a/main.rkt +++ b/main.rkt @@ -47,7 +47,9 @@ ;; set up a hook for identifier 'here' ;; (but under a different name to avoid macrofication) (define inner-here here) - (provide (all-defined-out))) + (provide (all-defined-out)) + (provide (all-from-out ; pollen file should bring its requires + (planet mb/pollen/tools)))) (require 'pollen-inner) ; provides doc & #%top, among other things diff --git a/regenerate.rkt b/regenerate.rkt index b27d463..c6b2321 100644 --- a/regenerate.rkt +++ b/regenerate.rkt @@ -61,8 +61,8 @@ ;; use rest argument here so calling pattern matches store-refresh (define/contract (mod-date-expired? . rest-paths) (() #:rest (listof path?) . ->* . boolean?) - (or (not (rest-paths . in? . mod-dates)) ; no stored mod date - (not (equal? (map path->mod-date-value rest-paths) (get mod-dates rest-paths))))) ; data has changed + (or (not (rest-paths . in? . mod-dates)) ; no stored mod date + (not (equal? (map path->mod-date-value rest-paths) (get mod-dates rest-paths))))) ; data has changed (module+ test (reset-mod-dates) @@ -92,7 +92,8 @@ ;; this will catch pmap (pollen map) files [(pmap-source? path) (let ([pmap (dynamic-require path 'main)]) (regenerate-with-pmap pmap #:force force))] - [else (message "Regenerate: passing through" (->string (file-name-from-path path)))]))) + [(file-exists? path) (message "Regenerate: passing through" (->string (file-name-from-path path)))] + [else (error "File not found:" (->string (file-name-from-path path)))]))) ;; todo: write tests @@ -108,18 +109,30 @@ (message "Regenerated:" (->string (file-name-from-path path)))) -(define/contract (regenerate-with-preproc x #:force [force #f]) - ((pathish?) (#:force boolean?) . ->* . void?) +;; 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 (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 - (define-values (source-path output-path) (if (preproc-source? path) - (values path (make-preproc-output-path path)) - (values (make-preproc-source-path path) path))) + (define source-path (complete-preproc-source-path x)) + (define output-path (complete-preproc-output-path x)) - ;; Computing the source-path doesn't validate whether it exists. - ;; Which is important, of course. - (if (file-exists? source-path) ;; Three conditions under which we refresh: (if (or ;; 1) explicitly forced refresh @@ -141,16 +154,14 @@ (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)))) - ;; source-path doesn't exist - (message "Preprocessor file not found:" (->string (file-name-from-path source-path))))) + (message "File is up to date:" (->string (file-name-from-path output-path))))) ;; todo: write tests ;; utility function for regenerate-with-template (define/contract (handle-source-rerequire source-path) - (path? . -> . boolean?) + ((and/c path? file-exists?) . -> . boolean?) ;; dynamic-rerequire watches files to see if they change. ;; if so, then it reloads them. @@ -176,14 +187,20 @@ ;; this becomes the return value (->boolean (> (len (get-output-string port-for-catching-file-info)) 0))) +(define (complete-pollen-source-path x) + (->complete-path (make-pollen-source-path (->path x)))) ;; apply template (define/contract (regenerate-with-template x [template-name #f] #:force [force #f]) - ((pathish?) (path? #:force boolean?) . ->* . void?) + (((and/c pathish? + (flat-named-contract 'file-exists + (λ(x) (file-exists? (complete-pollen-source-path x)))))) + (path? #:force boolean?) . ->* . void?) ;; set up information about source - (define source-path (->complete-path (make-pollen-source-path (->path x)))) - (define-values (source-dir source-name _) (split-path source-path)) + (define source-path (complete-pollen-source-path x)) + ;; todo: this won't work with source files nested down one level + (define-values (source-dir ignored also-ignored) (split-path source-path)) ;; find out whether source had to be reloaded (define source-reloaded? (handle-source-rerequire source-path)) @@ -193,9 +210,8 @@ ;; 1) Set the template. (define template-path (build-path source-dir - ;; if template name provided and exists + ;; if template name provided and exists, use that (if (and template-name (file-exists? (build-path source-dir template-name))) - ;; OK to use template-name as given template-name ;; Otherwise — try to get template name out of meta fields. ;; todo: consider that template file in metas @@ -230,12 +246,13 @@ (define/contract (render-source-with-template source-path template-path) - (complete-path? complete-path? . -> . string?) + (file-exists? file-exists? . -> . string?) ;; set up information about source and template paths + ;; todo: how to write these without blanks? (define-values (source-dir source-name _) (split-path source-path)) - (define-values (template-dir template-name __) (split-path template-path)) - + (define-values (___ template-name __) (split-path template-path)) + ;; Templates are part of the compile operation. ;; Therefore no way to arbitrarily invoke template at run-time. ;; This routine creates a new namespace and compiles the template within it. @@ -247,10 +264,9 @@ [current-directory source-dir] [current-output-port (open-output-nowhere)]) (namespace-require 'racket) ; use namespace-require for FIRST require, then eval after - (eval '(require (only-in web-server/templates include-template)) (current-namespace)) + (eval '(require web-server/templates) (current-namespace)) (eval '(require (planet mb/pollen/pmap)) (current-namespace)) - ; import source into eval space, - ; automatically sets up main & metas & here + ;; import source into eval space. This sets up main & metas (eval `(require ,(path->string source-name)) (current-namespace)) (eval `(include-template #:command-char ,TEMPLATE_FIELD_DELIMITER ,(->string template-name)) (current-namespace)))) diff --git a/tests/bibliography.html b/tests/bibliography.html index 3b0b61e..5f43fcb 100644 --- a/tests/bibliography.html +++ b/tests/bibliography.html @@ -1 +1 @@ -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 +

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/subtest/test.p b/tests/subtest/test.p new file mode 100644 index 0000000..a95b37d --- /dev/null +++ b/tests/subtest/test.p @@ -0,0 +1,3 @@ +#lang planet mb/pollen + +This is a test of the regen system. \ No newline at end of file diff --git a/tests/test-requirer.p b/tests/test-requirer.p index 0e2ad82..7bc35af 100644 --- a/tests/test-requirer.p +++ b/tests/test-requirer.p @@ -1,13 +1 @@ #lang racket/base - -(require (planet mb/pollen/pmap)) - -; -;(require "test-pmap.p") -;(require "pollen-lang-test.p") - -(let ([left (make-page-sequence (main->pmap (dynamic-require "test.pmap" 'main)))] - [right (make-page-sequence (main->pmap (dynamic-require "test-pmap.p" 'main)))]) - (print left) - (print right) - (andmap (λ(l r) (equal? l r)) left right)) \ No newline at end of file diff --git a/tools.rkt b/tools.rkt index 84e69f0..3e8b2a4 100644 --- a/tools.rkt +++ b/tools.rkt @@ -1,7 +1,7 @@ #lang racket/base (require racket/contract racket/match) (require (only-in racket/format ~a)) -(require racket/list) +(require racket/list xml) (require (only-in racket/string string-join)) (require (only-in xml xexpr? xexpr/c)) @@ -215,3 +215,57 @@ (check-equal? (make-meta-hash '((meta "foo" "bar")(meta "foo" "haw"))) (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))))