Making The Blog Part 3: Implementing Tags
May 21, 2024I think that I've implemented tags. It's pretty neat.
The actual implementation had two major nits.
One is organizational. I didn't want to have arbitrary magic metadata floating around,
so I did what any good go template writer would do, and tossed all the important stuff
into a struct. Two structs, actually, though renderingPage
only gets filled in
juuuuuuuust before the page is put into the template. It has PagesByTag, which is
all pages in the parse ordered by Created date.
type parsedPage struct {
Template string
Parameters map[string]interface{}
Tags []string
Content *bytes.Buffer
dir os.DirEntry
Path string
Title string
Created time.Time
}
type renderingPage struct {
*parsedPage
PagesByTag map[string][]*parsedPage
}
The exported vars, Template, Parameters, Tags and everything, are available to the template. It's possible that Path will be restricted at some point in the future.
The other hairy part is that the the tags in the blog are not necessarily parsed by the goldmark Metadata parser as a []string, as I'd want, nor is the user (me) necessarily providing the tags as such. Maybe I provide only one tag, or accidentally nest too deep. In this case, I wanted to handle it safely. So here's the hairy code. I may in fact report errors, such as when the tags aren't strings, but for now, this is what I've got and I mostly just need to use it and see what feels right.
func readTags(metadata map[string]interface{}) ([]string, error) {
ts, ok := metadata["tags"]
if !ok {
return nil, nil
}
tst, ok := ts.(string)
if ok {
ret := make([]string, 1)
ret[0] = tst
return ret, nil
}
tsa, ok := ts.([]string)
if ok {
return tsa, nil
}
tso, ok := ts.([]interface{})
if ok {
ret := make([]string, len(tso))
for _, x := range tso {
xs, ok := x.(string)
if ok {
ret = append(ret, xs)
}
}
return ret, nil
}
return nil, nil
}
Probably doesn't pass readability. err is always nil, and can be deleted. Or, you know, return an error.
In any case, that's where I'm at. We're FeatureComplete baby! Now time for some templates!