From ce2dc58b4ceef3df2c18ffcf65b9755bf5507fda Mon Sep 17 00:00:00 2001 From: James Ian Johnson Date: Fri, 9 Mar 2012 18:04:46 -0500 Subject: [PATCH] Better disambiguation for autobib. Delays rendering bib elements because the disambiguation must be accounted for. original commit: f3dc5796bedcc4390382f0c9d6790caf68d11a99 --- collects/scriblib/autobib.rkt | 247 +++++++++++++------- collects/scriblib/scribblings/autobib.scrbl | 23 +- 2 files changed, 180 insertions(+), 90 deletions(-) diff --git a/collects/scriblib/autobib.rkt b/collects/scriblib/autobib.rkt index aacf29a3..685a525c 100644 --- a/collects/scriblib/autobib.rkt +++ b/collects/scriblib/autobib.rkt @@ -1,6 +1,7 @@ #lang at-exp racket/base (require scribble/manual racket/list + racket/date scribble/core scribble/decode scribble/html-properties @@ -27,65 +28,84 @@ (define bib-table-style (make-style "AutoBibliography" autobib-style-extras)) (define bibentry-style (make-style "Autobibentry" autobib-style-extras)) -(define-struct auto-bib (author date entry-element key specific)) +(define-struct auto-bib (author date title location url is-book? key specific)) (define-struct bib-group (ht)) (define-struct (author-element element) (names cite)) (define-struct (other-author-element author-element) ()) ;; render the use of a citation. -(define (add-cite group bib-entry which with-specific? with-disambiguation?) +(define (add-cite group bib-entry which with-specific? disambiguation) (let ([key (auto-bib-key bib-entry)]) (hash-set! (bib-group-ht group) key bib-entry) (make-delayed-element (lambda (renderer part ri) ;; (list which key) should be mapped to the bibliography element. (define s (resolve-get part ri `(,which ,key))) - (define disambiguation - (cond [(and with-disambiguation? - (resolve-get part ri `(autobib-disambiguation ,key))) - => - (λ (dis) - (case dis - [(unambiguous) '()] - [else - (list - (make-link-element #f (list dis) - `(autobib ,(auto-bib-key bib-entry))))]))] - [else '()])) (cons (make-link-element #f (list (or s "???") (if with-specific? (auto-bib-specific bib-entry) "")) `(autobib ,(auto-bib-key bib-entry))) - disambiguation)) + (cond [(and disambiguation + (or (pair? (cdr disambiguation)) + (and (null? (cdr disambiguation)) + ))) ;; should be a list of bib-entries with same author/date + (define disambiguation* + (add-between (for/list ([bib (in-list disambiguation)]) + (define maybe-disambiguation + (resolve-get part ri `(autobib-disambiguation ,(auto-bib-key bib)))) + (case maybe-disambiguation + [(unambiguous) #f] + [else maybe-disambiguation])) + ",")) + (cond [(not (car disambiguation*)) '()] ;; the bib was unambiguous + [else + (list (make-link-element #f (list disambiguation*) `(autobib ,(auto-bib-key bib-entry))))])] + [else '()]))) (lambda () "(???)") (lambda () "(???)")))) -(define (add-inline-cite group bib-entries) +(define (add-date-cites group bib-entries delimiter maybe-datenumber (auto-bib-date b))) +(define (extract-bib-key b) + (author-element-names (extract-bib-author b))) + +;; Defaults only care about the year. +(define (default-render-date-bib date) + (make-element #f (list (number->string (date-year date))))) +(define (default-render-date-cite date) + (make-element #f (list (number->string (date-year date))))) +(define (default-date a, 1 -> b, etc. (define (default-disambiguation n) (when (>= n 26) (error 'default-disambiguation "Citations too ambiguous for default disambiguation scheme.")) - (make-element #f (list (format " ~a" (integer->char (+ 97 n)))))) + (make-element #f (list (format "~a" (integer->char (+ 97 n)))))) -(define (gen-bib tag group sec-title maybe-disambiguator) +(define (gen-bib tag group sec-title maybe-disambiguator maybe-render-date-bib maybe-render-date-cite maybe-dateentry bib disambiguation render-date-bib)) `(autobib ,(auto-bib-key bib))))) ;; Communicate to scribble's resolve step. (define (collect ci) @@ -151,11 +183,11 @@ `(autobib-author ,(auto-bib-key bib)) ;; (list which key) (make-element #f - (list (author-element-cite (auto-bib-author bib))))) + (list (author-element-cite (extract-bib-author bib))))) ;; store the date (collect-put! ci `(autobib-date ,(auto-bib-key bib)) ;; (list which key) - (make-element #f (list (auto-bib-date bib)))) + (make-element #f (list (render-date-cite (auto-bib-date bib))))) ;; store how to disambiguate it from other like citations. (collect-put! ci `(autobib-disambiguation ,(auto-bib-key bib)) @@ -189,68 +221,109 @@ (list (make-table bib-table-style disambiguated)) null)) +(define (bib->entry bib disambiguation render-date-bib) + (define-values (author date title location url is-book?) + (values (auto-bib-author bib) + (auto-bib-date bib) + (auto-bib-title bib) + (auto-bib-location bib) + (auto-bib-url bib) + (auto-bib-is-book? bib))) + (make-element bibentry-style + (append + (if author + `(,author + ,@(if (ends-in-punc? author) + '(" ") + '(". "))) + null) + ;; (if is-book? null '(ldquo)) + (if is-book? + (list (italic title)) + (decode-content (list title))) + (if (ends-in-punc? title) + null + '(".")) + ;; (if is-book? null '(rdquo)) + (if location + `(" " ,@(decode-content (list location)) ,(if date "," ".")) + null) + (if date `(" " + @,(if disambiguation + `("(" ,@(decode-content (list (render-date-bib date))) ,disambiguation ")") + (decode-content (list (render-date-bib date)))) + ".") + null) + (if url `(" " ,(link url (make-element 'url (list url)))) null)))) + (define-syntax (define-cite stx) (syntax-parse stx - [(_ cite* citet generate-bibliography - (~optional (~seq #:disambiguate fn) - #:defaults ([fn #'#f]))) + [(_ (~var ~cite) citet generate-bibliography + (~or (~optional (~seq #:disambiguate fn) #:defaults ([fn #'#f])) + (~optional (~seq #:render-date-in-bib render-date-bib) #:defaults ([render-date-bib #'#f])) + (~optional (~seq #:render-date-in-cite render-date-cite) #:defaults ([render-date-cite #'#f])) + (~optional (~seq #:datestring e))) +(define (understand-date inp) + ;; Currently there is no string->date function. + ;; Common usage of autobib has assumed that this should be the year. + (cond [(or (string? inp) (number? inp)) + (define year + (cond [(string? inp) (string->number inp)] + [else inp])) + (date 0 0 0 1 1 ;; second/minute/hour/day/month + year + ;; week-day/year-day/daylight savings time?/timezone offset + 0 0 #f 0)] + [(date? inp) inp] + [(not inp) #f] ;; no date is fine too. + [else (error 'make-bib "Not given a value that represents a date.")])) + +;; We delay making the element for the bib-entry because we may need to add +;; disambiguations during gen-bib. (define (make-bib #:title title #:author [author #f] #:is-book? [is-book? #f] #:location [location #f] #:date [date #f] #:url [url #f]) - (let* ([author (cond - [(not author) #f] - [(author-element? author) author] - [else (parse-author author)])] - [content - (append - (if author - `(,author - ,@(if (ends-in-punc? author) - '(" ") - '(". "))) - null) - ;; (if is-book? null '(ldquo)) - (if is-book? - (list (italic title)) - (decode-content (list title))) - (if (ends-in-punc? title) - null - '(".")) - ;; (if is-book? null '(rdquo)) - (if location - `(" " ,@(decode-content (list location)) ,(if date "," ".")) - null) - (if date `(" " ,@(decode-content (list (to-string date))) ".") null) - (if url `(" " ,(link url (make-element 'url (list url)))) null))] - [elem (make-element bibentry-style content)]) - (make-auto-bib - (or author (org-author-name title)) - (to-string date) - elem - (content->string elem) - ""))) + (define author* + (cond [(not author) #f] + [(author-element? author) author] + [else (parse-author author)])) + (define parsed-date (understand-date date)) + (make-auto-bib author* parsed-date title location url is-book? + (content->string + (make-element bibentry-style + (append + (if author* (list author*) null) + (list title) + (if location (decode-content (list location)) null) + (if date (decode-content (list (default-render-date-bib parsed-date))) null) + (if url (link url (make-element 'url (list url))) null)))) + "")) (define (in-bib bib where) (make-auto-bib (auto-bib-author bib) (auto-bib-date bib) - (auto-bib-entry-element bib) + (auto-bib-title bib) + (auto-bib-location bib) + (auto-bib-url bib) + (auto-bib-is-book? bib) (auto-bib-key bib) ;; "where" is the only specific part of auto-bib elements currently. (string-append (auto-bib-specific bib) where))) diff --git a/collects/scriblib/scribblings/autobib.scrbl b/collects/scriblib/scribblings/autobib.scrbl index 986bdac7..209e3c3f 100644 --- a/collects/scriblib/scribblings/autobib.scrbl +++ b/collects/scriblib/scribblings/autobib.scrbl @@ -9,17 +9,31 @@ @defmodule[scriblib/autobib] -@defform[(define-cite ~cite-id citet-id generate-bibliography-id [#:disambiguate disambiguator])]{ +@defform[(define-cite ~cite-id citet-id generate-bibliography-id + [#:disambiguate disambiguator] + [#:render-date-bib render-date] + [#:render-date-cite render-date] + [#:date exact-nonnegative-integer? element?)] +Dates in citations and dates in the bibliography may be rendered differently, +as specified by the optionally given @racket[render-date] functions, which have the contract + +@racketblock[(-> date? element?)] + +The dates of citations are stored as @racket[date] values, and the granularity in which they are compared and rendered are, by default, by year. The comparison functions have contract + +@racketblock[(-> date? date? boolean?)] + The function bound to @racket[~cite-id] produces a citation referring to one or more bibliography entries with a preceding non-breaking space, by default sorting the entries to match the bibliography order. @@ -59,7 +73,7 @@ Returns @racket[#t] if @racket[v] is a value produced by [#:author author any/c #f] [#:is-book? is-book? any/c #f] [#:location location any/c #f] - [#:date date any/c #f] + [#:date date (or/c #f date? exact-nonnegative-integer? string?) #f] [#:url url string? #f]) bib?]{ @@ -70,6 +84,9 @@ supplied. Functions like @racket[proceedings-location], @racket[author-name], and @racket[authors] help produce elements in a standard format. +Dates are internally represented as @racket[date] values, so a @racket[date] +may be given, or a number or string that represent the year. + An element produced by a function like @racket[author-name] tracks first, last names, and name suffixes separately, so that names can be ordered and rendered correctly. When a string is provided as an author