start implementing metadata parsing support

Signed-off-by: Christine Dodrill <me@christine.website>
This commit is contained in:
Cadey Ratio 2021-04-29 13:39:52 +00:00
parent 12d9012c08
commit 539a943576
5 changed files with 177 additions and 0 deletions

105
gempub.go
View File

@ -1 +1,106 @@
// Package gempub implements the gempub 1.0.0 specification as described here: https://codeberg.org/oppenlab/gempub
package gempub
import (
"bufio"
"errors"
"fmt"
"io"
"strings"
"time"
)
type Metadata struct {
Title string // mandatory title of the work
GpubVersion string // mandatory Gempub format version: 1.0.0
Index string // path to index.gmi, if none is specified it should be assumed to be in the root
Author string // author of the work
Language string // BCP 47 language code
Charset string // if not set, assume UTF-8
Description string // human-readable description
Published time.Time // YYYY when date is unknown
PublishDate time.Time // YYYY-MM-DD eg. 2006-01-02
RevisionDate time.Time // YYYY-MM-DD eg. 2006-01-02
Copyright string // copyright of the book
License string // license of the book Version string a // human readable only, not meant to be parsed
Cover string // a JPG or PNG image which can be anywhere in the directory structure
}
var (
ErrNoTitle = errors.New("gempub: no title in document")
)
func loadDateOrYear(when string) (t time.Time, err error) {
if len(when) == 4 {
t, err = time.Parse("2006", when)
return
}
t, err = time.Parse("2006-01-02", when)
return
}
func (m Metadata) Valid() error {
switch {
case m.Title == "":
return ErrNoTitle
case m.GpubVersion != "1.0.0":
return fmt.Errorf("gempub: wrong gempub version: %v", m.GpubVersion)
}
return nil
}
func ReadMetadata(r io.Reader) (*Metadata, error) {
var result Metadata
sc := bufio.NewScanner(r)
for sc.Scan() {
line := sc.Text()
sp := strings.SplitN(line, ":", 2)
key, val := sp[0], sp[1]
val = strings.TrimSpace(val)
switch key {
case "title":
result.Title = val
case "gpubVersion":
result.GpubVersion = val
case "index":
result.Index = val
case "author":
result.Author = val
case "language":
result.Language = val
case "charset":
result.Charset = val
case "description":
result.Description = val
case "published":
when, err := loadDateOrYear(val)
if err != nil {
return nil, fmt.Errorf("gempub: can't understand date %q: %v", val, err)
}
result.Published = when
case "publishDate":
when, err := loadDateOrYear(val)
if err != nil {
return nil, fmt.Errorf("gempub: can't understand date %q: %v", val, err)
}
result.PublishDate = when
case "revisionDate":
when, err := loadDateOrYear(val)
if err != nil {
return nil, fmt.Errorf("gempub: can't understand date %q: %v", val, err)
}
result.RevisionDate = when
case "copyright":
result.Copyright = val
case "license":
result.License = val
case "cover":
result.Cover = val
}
}
return &result, result.Valid()
}

54
gempub_test.go Normal file
View File

@ -0,0 +1,54 @@
package gempub
import (
"embed"
"io/fs"
"testing"
)
//go:embed testdata/*
var testdata embed.FS
func TestGoodMetadata(t *testing.T) {
fnames, err := fs.Glob(testdata, "testdata/metadata/good/*")
if err != nil {
t.Fatal(err)
}
for _, fname := range fnames {
t.Run(fname, func(t *testing.T) {
fin, err := testdata.Open(fname)
if err != nil {
t.Fatal(err)
}
defer fin.Close()
md, err := ReadMetadata(fin)
if err != nil {
t.Fatal(err)
}
})
}
}
func TestBadMetadata(t *testing.T) {
fnames, err := fs.Glob(testdata, "testdata/metadata/bad/*")
if err != nil {
t.Fatal(err)
}
for _, fname := range fnames {
t.Run(fname, func(t *testing.T) {
fin, err := testdata.Open(fname)
if err != nil {
t.Fatal(err)
}
defer fin.Close()
_, err = ReadMetadata(fin)
if err == nil {
t.Fatal("wanted error, but got none")
}
})
}
}

0
testdata/metadata/bad/blank.txt vendored Normal file
View File

14
testdata/metadata/good/complete.txt vendored Normal file
View File

@ -0,0 +1,14 @@
title: Spellblade
gpubVersion: 1.0.0
index: book/index.gmi
author: Xe
language: en-US
charset: UTF-8
description: A woman realizes the gap between two opposites and their place in the middle.
published: 2021
publishDate: 2021-12-31
revisionDate: 2022-01-01
copyright: Christine Dodrill
license: All Rights Reserved
version: 1.0.0
cover: cover.jpg

4
testdata/metadata/good/simple.txt vendored Normal file
View File

@ -0,0 +1,4 @@
title: Star Maker
author: Olaf Stapledon
index: ./capsule/index.gmi
gpubVersion: 1.0.0