From dce6fe3e40b8d68000df2902d3858b0874aa77b5 Mon Sep 17 00:00:00 2001 From: Masaya Tojo Date: Sun, 24 Mar 2024 21:09:55 +0900 Subject: Add read-article procedure. --- readers/article.rkt | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 readers/article.rkt (limited to 'readers') diff --git a/readers/article.rkt b/readers/article.rkt new file mode 100644 index 0000000..8f06b95 --- /dev/null +++ b/readers/article.rkt @@ -0,0 +1,57 @@ +#lang typed/racket + +(provide read-article) + +(require "../entities/article.rkt") +(require (only-in typed/srfi/19 string->date)) +(require typed/json) +(require typed/syntax/readerr) + +(: json->article (-> JSExpr (U Article-With-Tags String))) +(define (json->article jse) + (call/cc + (lambda ([k : (-> String Nothing)]) + (unless (hash? jse) (k "must be a hash")) + (define id (hash-ref jse 'id (thunk (k "id not found")))) + (unless (string? id) (k "id must be a string")) + (define timestamp + (let ([timestamp (hash-ref jse 'timestamp (thunk (k "timestamp not found")))]) + (unless (string? timestamp) (k "timestamp must be a string")) + (with-handlers ([exn:fail? (const #f)]) + (string->date timestamp "~Y-~m-~dT~H:~M:~S~z")))) + (unless (date? timestamp) (k "timestamp must be a iso8600 string")) + + (define hash (hash-ref jse 'hash (thunk (k "hash not found")))) + (unless (string? hash) (k "hash must be a string")) + + (define title (hash-ref jse 'title (thunk (k "title not found")))) + (unless (string? title) (k "title must be a string")) + + (define tags (hash-ref jse 'tags (thunk (k "tags not found")))) + (unless (list? tags) (k "tags must be a list")) + (unless (andmap string? tags) (k "element of tag must be a string")) + + (define body (hash-ref jse 'html (thunk (k "html not found")))) + (unless (string? body) (k "html must be a string")) + + (make-article-with-tags id timestamp hash title body tags)))) + +(: read-article (-> Input-Port (U Article-With-Tags EOF))) +(define (read-article in) + (let-values ([(l c p) (port-next-location in)]) + (let ([json (read-json in)]) + (cond + [(eof-object? json) eof] + [else + (let ([article (json->article json)]) + (cond + [(article-with-tags? article) article] + [else + (let-values ([(_nl nc np) (port-next-location in)]) + (raise-read-error (format "read-article: ~a" article) + (object-name in) + l c p + (and p np + (let ([np-p (- np p)]) + (and (exact-positive-integer? np-p) + np-p)))))]))])))) -- cgit v1.2.3