@@ -19,26 +19,114 @@ ;; Author contact information: ;; joel@jdueck.net ;; https://joeldueck.com ;; ------------------------------------------------------------------------- -;; Convenience functions for YYYY-MM-DD date strings - -(require gregor +(require pollen/core + pollen/pagetree + net/uri-codec + gregor + txexpr + racket/list racket/string) -(provide (all-defined-out)) +;; Provides common helper functions used throughout the project + +(provide maybe-meta ; Select from (current-metas) or default value ("") if not available + maybe-attr ; Return an attribute’s value or a default ("") if not available + series-noun ; Retrieve noun-singular from current 'series meta, or "" + attr-present? ; Test if an attribute is present + disposition-values + ymd->english + ymd->dateformat + default-authorname + default-title + tx-strs + build-note-id + notes->last-disposition-values + ) + +(define default-authorname "Joel Dueck") + +(define (default-title date) + (format "Entry of ~a" (ymd->dateformat date "d MMM YYYY"))) + +(define (maybe-meta m [missing ""]) + (or (select-from-metas m (current-metas)) missing)) + +(define (series-noun) + (define series-pagenode (->pagenode (or (select-from-metas 'series (current-metas)) ""))) + (case series-pagenode + ['|| ""] ; no series specified + [else (or (select-from-metas 'noun-singular series-pagenode) "")])) + +(define (attr-present? name attrs) + (for/or ([attr-pair (in-list attrs)]) + (equal? name (car attr-pair)))) + +(define (maybe-attr name attrs [missing ""]) + (define result (assoc name attrs)) + (cond + [(pair? result) (cadr result)] + [else missing])) + +(define (tx-strs xpr) + (cond + [(txexpr? xpr) (apply string-append (map tx-strs (get-elements xpr)))] + [(string? xpr) xpr] + [else ""])) + +(module+ test + (require rackunit) + (define test-metas (hash 'name "Fiver" 'size "Small")) + (define test-attrs '([name "Hazel"] [rank "Chief"])) + + (parameterize ([current-metas test-metas]) + (check-equal? (maybe-meta 'name) "Fiver") ; present meta + (check-equal? (maybe-meta 'age) "") ; missing meta + (check-equal? (maybe-meta 'age 2) 2)) ; alternate default value + + (check-equal? (attr-present? 'name test-attrs) #t) + (check-equal? (attr-present? 'dingus test-attrs) #f) + (check-equal? (maybe-attr 'rank test-attrs) "Chief") + (check-equal? (maybe-attr 'dingus test-attrs) "") + (check-equal? (maybe-attr 'dingus test-attrs "zippy") "zippy")) + +;; Convert, e.g., "* thoroughly recanted" into (values "*" "thoroughly recanted") +(define (disposition-values str) + (cond [(string=? "" str) (values "" "")] + [else (let ([splut (string-split str)]) + (values (car splut) (string-join (cdr splut))))])) + +;; The format of a note’s ID is “HTML-driven” (used as an anchor link) but is included +;; here since it also serves as a primary key in the DB. +(define (build-note-id txpr) + (string-append "#" + (maybe-attr 'date (get-attrs txpr)) + "_" + (uri-encode (maybe-attr 'author (get-attrs txpr) default-authorname)))) + +;; Extract the last disposition (if any), and the ID of the disposing note, out of a list of notes +(define (notes->last-disposition-values txprs) + (define (contains-disposition? tx) (attr-present? 'disposition (get-attrs tx))) + (define disp-notes (filter contains-disposition? txprs)) + (cond [(not (empty? disp-notes)) + (define latest-disposition-note (last disp-notes)) + (values (attr-ref latest-disposition-note 'disposition) + (build-note-id latest-disposition-note))] + [else (values "" "")])) + +;; ~~~ Convenience functions for YYYY-MM-DD date strings ~~~ -;; These functions ignore everything after the first space! +;; These functions ignore everything after the first space in the input! (define (ymd->dateformat ymd-string dateformat) (~t (iso8601->date (car (string-split ymd-string))) dateformat)) (define (ymd->english ymd-string) (ymd->dateformat ymd-string "MMMM d, yyyy")) (module+ test - (require rackunit) (check-equal? (ymd->english "2018-08-12") "August 12, 2018") (check-equal? (ymd->dateformat "2018-08-12" "d MMM YYYY") "12 Aug 2018") ;; How we handle weird input (check-equal? (ymd->english "2018-08-12 everything after 1st space ignored") "August 12, 2018")