Add category pkg

This supports categories in Write.as / WriteFreely.

Ref T809
This commit is contained in:
Matt Baer
2021-09-29 17:01:17 -04:00
parent ee6bf8e8b7
commit a8daef8401
5 changed files with 93 additions and 0 deletions
+30
View File
@@ -0,0 +1,30 @@
// Package category supports post categories
package category
import (
"errors"
"github.com/writeas/slug"
)
var (
ErrNotFound = errors.New("category doesn't exist")
)
// Category represents a post tag with additional metadata, like a title and slug.
type Category struct {
ID int64 `json:"-"`
Hashtag string `json:"hashtag"`
Slug string `json:"slug"`
Title string `json:"title"`
}
// NewCategory creates a Category you can insert into the database, based on a hashtag. It automatically breaks up the
// hashtag by words, based on capitalization, for both the title and a URL-friendly slug.
func NewCategory(hashtag string) *Category {
title := titleFromHashtag(hashtag)
return &Category{
Hashtag: hashtag,
Slug: slug.Make(title),
Title: title,
}
}
+26
View File
@@ -0,0 +1,26 @@
package category
import (
"strings"
"unicode"
)
// titleFromHashtag generates an all-lowercase title, with spaces inserted based on initial capitalization -- e.g.
// "MyWordyTag" becomes "my wordy tag".
func titleFromHashtag(hashtag string) string {
var t strings.Builder
var prev rune
for i, c := range hashtag {
if unicode.IsUpper(c) {
if i > 0 && !unicode.IsUpper(prev) {
// Insert space if previous rune wasn't also uppercase (e.g. an abbreviation)
t.WriteRune(' ')
}
t.WriteRune(unicode.ToLower(c))
} else {
t.WriteRune(c)
}
prev = c
}
return t.String()
}
+31
View File
@@ -0,0 +1,31 @@
package category
import "testing"
func TestTitleFromHashtag(t *testing.T) {
tests := []struct {
name string
hashtag string
expTitle string
}{
{"proper noun", "Jane", "jane"},
{"full name", "JaneDoe", "jane doe"},
{"us words", "unitedStates", "united states"},
{"usa", "USA", "usa"},
{"us monoword", "unitedstates", "unitedstates"},
{"100dto", "100DaysToOffload", "100 days to offload"},
{"iphone", "iPhone", "iphone"},
{"ilike", "iLikeThis", "i like this"},
{"abird", "aBird", "a bird"},
{"all caps", "URGENT", "urgent"},
{"smartphone", "スマートフォン", "スマートフォン"},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
res := titleFromHashtag(test.hashtag)
if res != test.expTitle {
t.Fatalf("#%s: got '%s' expected '%s'", test.hashtag, res, test.expTitle)
}
})
}
}