racket/collects/meta/web/www/bib.rkt
2010-07-23 22:28:47 -05:00

157 lines
6.1 KiB
Racket

#lang at-exp s-exp "shared.rkt"
(require scheme/list scheme/string scheme/dict scheme/promise scheme/function)
;; bib values are hash tables mapping field names (symbols) to strings.
;; Keywords can also be used for the field names, which makes them meta-fields
;; that are not included in the usual bib printout. Two of them are required:
;; - #:type the type of the entry (a symbol: 'article, 'techreport, etc)
;; - #:key the label for the entry
(define bib-fields
'(author editor title booktitle journal
edition volume number series
chapter pages
type
school institution organization
publisher howpublished
address
month year
key
crossref
url
note
eprint))
(define meta-field? keyword?)
(define key->number
(let ([t (for/hash ([k bib-fields] [i (in-naturals)]) (values k i))])
(lambda (key)
(hash-ref t key (lambda ()
(error 'key->number "unknown field name: ~e" key))))))
;; converts the hash to an alist with the order specified by bib-fields
(define (bib->alist bib)
(sort (filter-not (compose meta-field? car) (hash-map bib cons))
< #:key (compose key->number car) #:cache-keys? #t))
(define (display* . xs)
(for-each display xs))
(define (display-attr attr)
(let* ([prefix (format " ~a = {" (car attr))]
[sep (delay (string-append "\n" (make-string (string-length prefix)
#\space)))])
(display* prefix
(if (regexp-match? #rx"\n" (cdr attr))
(regexp-replace* #rx"\n" (cdr attr) (force sep))
(cdr attr))
"}")))
(provide display-bib)
(define (display-bib bib)
(display* "@" (hash-ref bib '#:type) "{" (hash-ref bib '#:key))
(for ([attr (bib->alist bib)]) (display* ",\n") (display-attr attr))
(display* "\n}\n"))
(provide with-braces without-braces)
(define (with-braces str) (regexp-replace* #px"\\b\\w+[A-Z]\\w*" str "{\\0}"))
(define (without-braces str) (regexp-replace* #rx"[{}]+" str ""))
(provide bib-author)
(define (bib-author bib)
(let ([authors (regexp-split #rx"[ \t\n]+and[ \t\n]+"
(hash-ref bib 'author))])
(case (length authors)
[(0) "???"]
[(1) (car authors)]
[(2) (apply format "~a and ~a" authors)]
[(3) (apply format "~a, ~a, and ~a" authors)]
[else (format "~a et al" (car authors))])))
;; ----------------------------------------------------------------------------
;; processes the (key val ...) alist to a hash of (key . val) by combining the
;; possibly multiple values for each key (each value becomes a line)
(provide bib)
(define (bib type key attrs)
(define t (make-hasheq))
(hash-set! t '#:type type)
(hash-set! t '#:key key)
(for ([a attrs])
(define (err) (error 'make-bib "bad attribute: ~e" a))
(unless (and (pair? a) (pair? (cdr a)) (list? (cdr a))) (err))
(let ([key (car a)])
(unless (hash-ref t key #f) ; previous keys take precedence
(cond [(symbol? key)
;; turn non-strings to strings, join multiple strings, normalize
;; spaces
(let* ([val (cdr a)]
[val (map (lambda (x) (if (string? x) x (format "~a" x)))
val)]
[val (string-append* (add-between val "\n"))]
[val (regexp-replace* #rx"\t" val " ")]
[val (regexp-replace* #rx" +" val " ")]
[val (regexp-replace #rx"^ +" val "")]
[val (regexp-replace #rx" +$" val "")]
[val (regexp-replace* #rx"(?: *\r?\n *)+" val "\n")])
(hash-set! t key val))]
[(and (meta-field? key) (null? (cddr a)))
(hash-set! t key (cadr a))]
[else (err)]))))
t)
;; ----------------------------------------------------------------------------
#|
In the future, it might be good to do some field verification, etc. From the
bibtext thing:
article: An article from a journal or magazine.
req: author, title, journal, year
opt: volume, number, pages, month, note
book: A book with an explicit publisher.
req: author or editor, title, publisher, year
opt: volume or number, series, address, edition, month, note
booklet: A work that is printed and bound, but without a named publisher or
sponsoring institution.
req: title
opt: author, howpublished, address, month, year, note
conference: The same as `inproceedings', included for Scribe compatibility.
inbook: A part of a book, which may be a chapter (or section or whatever)
and/or a range of pages.
req: author or editor, title, chapter and/or pages, publisher, year
opt: volume or number, series, type, address, edition, month, note
incollection: A part of a book having its own title.
req: author, title, booktitle, publisher, year
opt: editor, volume or number, series, type, chapter, pages, address,
edition, month, note
inproceedings: An article in a conference proceedings.
req: author, title, booktitle, year
opt: editor, volume or number, series, pages, address, month, organization,
publisher, note
manual: Technical documentation.
req: title
opt: author, organization, address, edition, month, year, note
mastersthesis: A Master's thesis.
req: author, title, school, year
opt: type, address, month, note
misc: Use this type when nothing else fits.
opt: author, title, howpublished, month, year, note
phdthesis: A PhD thesis.
req: author, title, school, year
opt: type, address, month, note
proceedings: The proceedings of a conference.
req: title, year
opt: editor, volume or number, series, address, month, organization,
publisher, note
techreport: A report published by a school or other institution, usually
numbered within a series.
req: author, title, institution, year
opt: type, number, address, month, note
unpublished: A document having an author and title, but not formally
published.
req: author, title, note
opt: month, year
|#