mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-07 20:30:36 -05:00
Renamed Indexes to Taxonomies. Old template and config parameters still work.
This commit is contained in:
parent
aae6fa0b6b
commit
93bcddebb3
8 changed files with 171 additions and 150 deletions
|
@ -84,6 +84,8 @@ func InitializeConfig() {
|
|||
viper.AddConfigPath(Source)
|
||||
viper.ReadInConfig()
|
||||
|
||||
viper.RegisterAlias("taxonomies", "indexes")
|
||||
|
||||
viper.SetDefault("ContentDir", "content")
|
||||
viper.SetDefault("LayoutDir", "layouts")
|
||||
viper.SetDefault("StaticDir", "static")
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
package hugolib
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSitePossibleIndexes(t *testing.T) {
|
||||
site := new(Site)
|
||||
page, _ := ReadFrom(strings.NewReader(PAGE_YAML_WITH_INDEXES_A), "path/to/page")
|
||||
site.Pages = append(site.Pages, page)
|
||||
indexes := site.possibleIndexes()
|
||||
if !compareStringSlice(indexes, []string{"tags", "categories"}) {
|
||||
if !compareStringSlice(indexes, []string{"categories", "tags"}) {
|
||||
t.Fatalf("possible indexes do not match [tags categories]. Got: %s", indexes)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,22 +5,22 @@ import (
|
|||
"testing"
|
||||
)
|
||||
|
||||
var PAGE_YAML_WITH_INDEXES_A = `---
|
||||
var PAGE_YAML_WITH_TAXONOMIES_A = `---
|
||||
tags: ['a', 'b', 'c']
|
||||
categories: 'd'
|
||||
---
|
||||
YAML frontmatter with tags and categories index.`
|
||||
YAML frontmatter with tags and categories taxonomy.`
|
||||
|
||||
var PAGE_YAML_WITH_INDEXES_B = `---
|
||||
var PAGE_YAML_WITH_TAXONOMIES_B = `---
|
||||
tags:
|
||||
- "a"
|
||||
- "b"
|
||||
- "c"
|
||||
categories: 'd'
|
||||
---
|
||||
YAML frontmatter with tags and categories index.`
|
||||
YAML frontmatter with tags and categories taxonomy.`
|
||||
|
||||
var PAGE_JSON_WITH_INDEXES = `{
|
||||
var PAGE_JSON_WITH_TAXONOMIES = `{
|
||||
"categories": "d",
|
||||
"tags": [
|
||||
"a",
|
||||
|
@ -30,19 +30,19 @@ var PAGE_JSON_WITH_INDEXES = `{
|
|||
}
|
||||
JSON Front Matter with tags and categories`
|
||||
|
||||
var PAGE_TOML_WITH_INDEXES = `+++
|
||||
var PAGE_TOML_WITH_TAXONOMIES = `+++
|
||||
tags = [ "a", "b", "c" ]
|
||||
categories = "d"
|
||||
+++
|
||||
TOML Front Matter with tags and categories`
|
||||
|
||||
func TestParseIndexes(t *testing.T) {
|
||||
for _, test := range []string{PAGE_TOML_WITH_INDEXES,
|
||||
PAGE_JSON_WITH_INDEXES,
|
||||
PAGE_YAML_WITH_INDEXES_A,
|
||||
PAGE_YAML_WITH_INDEXES_B,
|
||||
func TestParseTaxonomies(t *testing.T) {
|
||||
for _, test := range []string{PAGE_TOML_WITH_TAXONOMIES,
|
||||
PAGE_JSON_WITH_TAXONOMIES,
|
||||
PAGE_YAML_WITH_TAXONOMIES_A,
|
||||
PAGE_YAML_WITH_TAXONOMIES_B,
|
||||
} {
|
||||
p, err := ReadFrom(strings.NewReader(test), "page/with/index")
|
||||
p, err := ReadFrom(strings.NewReader(test), "page/with/taxonomy")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed parsing %q: %s", test, err)
|
||||
}
|
129
hugolib/site.go
129
hugolib/site.go
|
@ -48,7 +48,7 @@ var DefaultTimer *nitro.B
|
|||
// various targets that will get generated. There will be canonical
|
||||
// listing. The canonical path can be overruled based on a pattern.
|
||||
//
|
||||
// 3. Indexes are created via configuration and will present some aspect of
|
||||
// 3. Taxonomies are created via configuration and will present some aspect of
|
||||
// the final page and typically a perm url.
|
||||
//
|
||||
// 4. All Pages are passed through a template based on their desired
|
||||
|
@ -58,9 +58,9 @@ var DefaultTimer *nitro.B
|
|||
type Site struct {
|
||||
Pages Pages
|
||||
Tmpl bundle.Template
|
||||
Indexes IndexList
|
||||
Taxonomies TaxonomyList
|
||||
Source source.Input
|
||||
Sections Index
|
||||
Sections Taxonomy
|
||||
Info SiteInfo
|
||||
Shortcodes map[string]ShortcodeFunc
|
||||
timer *nitro.B
|
||||
|
@ -73,7 +73,8 @@ type Site struct {
|
|||
|
||||
type SiteInfo struct {
|
||||
BaseUrl template.URL
|
||||
Indexes IndexList
|
||||
Taxonomies TaxonomyList
|
||||
Indexes *TaxonomyList // legacy, should be identical to Taxonomies
|
||||
Recent *Pages
|
||||
LastChange time.Time
|
||||
Title string
|
||||
|
@ -147,7 +148,7 @@ func (s *Site) Process() (err error) {
|
|||
if err = s.BuildSiteMeta(); err != nil {
|
||||
return
|
||||
}
|
||||
s.timerStep("build indexes")
|
||||
s.timerStep("build taxonomies")
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -168,13 +169,13 @@ func (s *Site) Render() (err error) {
|
|||
return
|
||||
}
|
||||
s.timerStep("render and write aliases")
|
||||
if err = s.RenderIndexes(); err != nil {
|
||||
if err = s.RenderTaxonomiesLists(); err != nil {
|
||||
return
|
||||
}
|
||||
s.timerStep("render and write indexes")
|
||||
s.RenderIndexesIndexes()
|
||||
s.timerStep("render & write index indexes")
|
||||
if err = s.RenderLists(); err != nil {
|
||||
s.timerStep("render and write taxonomies")
|
||||
s.RenderListsOfTaxonomyTerms()
|
||||
s.timerStep("render & write taxonomy lists")
|
||||
if err = s.RenderSectionLists(); err != nil {
|
||||
return
|
||||
}
|
||||
s.timerStep("render and write lists")
|
||||
|
@ -299,14 +300,14 @@ func (s *Site) CreatePages() (err error) {
|
|||
}
|
||||
|
||||
func (s *Site) BuildSiteMeta() (err error) {
|
||||
s.Indexes = make(IndexList)
|
||||
s.Sections = make(Index)
|
||||
s.Taxonomies = make(TaxonomyList)
|
||||
s.Sections = make(Taxonomy)
|
||||
|
||||
indexes := viper.GetStringMapString("Indexes")
|
||||
jww.INFO.Printf("found indexes: %#v\n", indexes)
|
||||
taxonomies := viper.GetStringMapString("Taxonomies")
|
||||
jww.INFO.Printf("found taxonomies: %#v\n", taxonomies)
|
||||
|
||||
for _, plural := range indexes {
|
||||
s.Indexes[plural] = make(Index)
|
||||
for _, plural := range taxonomies {
|
||||
s.Taxonomies[plural] = make(Taxonomy)
|
||||
for _, p := range s.Pages {
|
||||
vals := p.GetParam(plural)
|
||||
weight := p.GetParam(plural + "_weight")
|
||||
|
@ -320,15 +321,15 @@ func (s *Site) BuildSiteMeta() (err error) {
|
|||
for _, idx := range v {
|
||||
x := WeightedPage{weight.(int), p}
|
||||
|
||||
s.Indexes[plural].Add(idx, x)
|
||||
s.Taxonomies[plural].Add(idx, x)
|
||||
}
|
||||
} else {
|
||||
jww.ERROR.Printf("Invalid %s in %s\n", plural, p.File.FileName)
|
||||
}
|
||||
}
|
||||
}
|
||||
for k := range s.Indexes[plural] {
|
||||
s.Indexes[plural][k].Sort()
|
||||
for k := range s.Taxonomies[plural] {
|
||||
s.Taxonomies[plural][k].Sort()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -340,7 +341,8 @@ func (s *Site) BuildSiteMeta() (err error) {
|
|||
s.Sections[k].Sort()
|
||||
}
|
||||
|
||||
s.Info.Indexes = s.Indexes
|
||||
s.Info.Taxonomies = s.Taxonomies
|
||||
s.Info.Indexes = &s.Taxonomies
|
||||
|
||||
if len(s.Pages) == 0 {
|
||||
return
|
||||
|
@ -355,11 +357,11 @@ func (s *Site) BuildSiteMeta() (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func (s *Site) possibleIndexes() (indexes []string) {
|
||||
func (s *Site) possibleTaxonomies() (taxonomies []string) {
|
||||
for _, p := range s.Pages {
|
||||
for k := range p.Params {
|
||||
if !inStringArray(indexes, k) {
|
||||
indexes = append(indexes, k)
|
||||
if !inStringArray(taxonomies, k) {
|
||||
taxonomies = append(taxonomies, k)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -375,6 +377,7 @@ func inStringArray(arr []string, el string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// Render shell pages that simply have a redirect in the header
|
||||
func (s *Site) RenderAliases() error {
|
||||
for _, p := range s.Pages {
|
||||
for _, a := range p.Aliases {
|
||||
|
@ -390,12 +393,13 @@ func (s *Site) RenderAliases() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Render pages each corresponding to a markdown file
|
||||
func (s *Site) RenderPages() (err error) {
|
||||
var wg sync.WaitGroup
|
||||
for _, page := range s.Pages {
|
||||
wg.Add(1)
|
||||
go func(p *Page) (err error) {
|
||||
var layout []string
|
||||
var layouts []string
|
||||
defer wg.Done()
|
||||
|
||||
if !p.IsRenderable() {
|
||||
|
@ -404,13 +408,13 @@ func (s *Site) RenderPages() (err error) {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
layout = append(layout, self)
|
||||
layouts = append(layouts, self)
|
||||
} else {
|
||||
layout = append(layout, p.Layout()...)
|
||||
layout = append(layout, "_default/single.html")
|
||||
layouts = append(layouts, p.Layout()...)
|
||||
layouts = append(layouts, "_default/single.html")
|
||||
}
|
||||
|
||||
return s.render(p, p.TargetPath(), layout...)
|
||||
return s.render(p, p.TargetPath(), layouts...)
|
||||
}(page)
|
||||
}
|
||||
wg.Wait()
|
||||
|
@ -421,12 +425,14 @@ func (s *Site) RenderPages() (err error) {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *Site) RenderIndexes() (err error) {
|
||||
// Render the listing pages based on the meta data
|
||||
// each unique term within a taxonomy will have a page created
|
||||
func (s *Site) RenderTaxonomiesLists() (err error) {
|
||||
var wg sync.WaitGroup
|
||||
|
||||
indexes := viper.GetStringMapString("Indexes")
|
||||
for sing, pl := range indexes {
|
||||
for key, oo := range s.Indexes[pl] {
|
||||
taxonomies := viper.GetStringMapString("Taxonomies")
|
||||
for sing, pl := range taxonomies {
|
||||
for key, oo := range s.Taxonomies[pl] {
|
||||
wg.Add(1)
|
||||
go func(k string, o WeightedPages, singular string, plural string) (err error) {
|
||||
defer wg.Done()
|
||||
|
@ -437,8 +443,8 @@ func (s *Site) RenderIndexes() (err error) {
|
|||
n.Date = o[0].Page.Date
|
||||
n.Data[singular] = o
|
||||
n.Data["Pages"] = o.Pages()
|
||||
layout := "indexes/" + singular + ".html"
|
||||
err = s.render(n, base+".html", layout)
|
||||
err = s.render(n, base+".html", "taxonomies/"+singular+".html", "indexes/"+singular+".html")
|
||||
//TODO add , "_default/taxonomy.html", "_default/list.html"
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -447,6 +453,7 @@ func (s *Site) RenderIndexes() (err error) {
|
|||
// XML Feed
|
||||
s.setUrls(n, base+".xml")
|
||||
err := s.render(n, base+".xml", "rss.xml")
|
||||
// TODO add "taxonomy.xml", "_internal/rss.xml"
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -459,22 +466,25 @@ func (s *Site) RenderIndexes() (err error) {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *Site) RenderIndexesIndexes() (err error) {
|
||||
layout := "indexes/indexes.html"
|
||||
if s.Tmpl.Lookup(layout) != nil {
|
||||
|
||||
indexes := viper.GetStringMapString("Indexes")
|
||||
for singular, plural := range indexes {
|
||||
// Render a page per taxonomy that lists the terms for that taxonomy
|
||||
func (s *Site) RenderListsOfTaxonomyTerms() (err error) {
|
||||
layouts := []string{"taxonomies/termslist.html", "indexes/indexes.html"}
|
||||
// TODO add "_default/termsList.html", "_default/termslist.html"
|
||||
// TODO add support for unique taxonomy terms list (`single`terms.html)
|
||||
if s.layoutExists(layouts...) {
|
||||
taxonomies := viper.GetStringMapString("Taxonomies")
|
||||
for singular, plural := range taxonomies {
|
||||
n := s.NewNode()
|
||||
n.Title = strings.Title(plural)
|
||||
s.setUrls(n, plural)
|
||||
n.Data["Singular"] = singular
|
||||
n.Data["Plural"] = plural
|
||||
n.Data["Index"] = s.Indexes[plural]
|
||||
n.Data["Terms"] = s.Taxonomies[plural]
|
||||
// keep the following just for legacy reasons
|
||||
n.Data["OrderedIndex"] = s.Indexes[plural]
|
||||
n.Data["OrderedIndex"] = n.Data["Terms"]
|
||||
n.Data["Index"] = n.Data["Terms"]
|
||||
|
||||
err := s.render(n, plural+"/index.html", layout)
|
||||
err := s.render(n, plural+"/index.html", layouts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -483,16 +493,16 @@ func (s *Site) RenderIndexesIndexes() (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func (s *Site) RenderLists() error {
|
||||
// Render a page for each section
|
||||
func (s *Site) RenderSectionLists() error {
|
||||
for section, data := range s.Sections {
|
||||
n := s.NewNode()
|
||||
n.Title = strings.Title(inflect.Pluralize(section))
|
||||
s.setUrls(n, section)
|
||||
n.Date = data[0].Page.Date
|
||||
n.Data["Pages"] = data.Pages()
|
||||
layout := "indexes/" + section + ".html"
|
||||
|
||||
err := s.render(n, section, layout, "_default/indexes.html")
|
||||
err := s.render(n, section, "section/"+section+".html", "indexes/"+section+".html", "_default/section.html", "_default/list.html", "_default/indexes.html")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -501,6 +511,8 @@ func (s *Site) RenderLists() error {
|
|||
// XML Feed
|
||||
s.setUrls(n, section+".xml")
|
||||
err = s.render(n, section+".xml", "rss.xml")
|
||||
//TODO add section specific rss
|
||||
// TODO add internal rss
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -533,6 +545,7 @@ func (s *Site) RenderHomePage() error {
|
|||
n.Date = s.Pages[0].Date
|
||||
}
|
||||
err := s.render(n, ".xml", "rss.xml")
|
||||
// TODO add internal RSS
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -551,10 +564,10 @@ func (s *Site) RenderHomePage() error {
|
|||
func (s *Site) Stats() {
|
||||
jww.FEEDBACK.Printf("%d pages created \n", len(s.Pages))
|
||||
|
||||
indexes := viper.GetStringMapString("Indexes")
|
||||
taxonomies := viper.GetStringMapString("Taxonomies")
|
||||
|
||||
for _, pl := range indexes {
|
||||
jww.FEEDBACK.Printf("%d %s index created\n", len(s.Indexes[pl]), pl)
|
||||
for _, pl := range taxonomies {
|
||||
jww.FEEDBACK.Printf("%d %s created\n", len(s.Taxonomies[pl]), pl)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -587,10 +600,16 @@ func (s *Site) NewNode() *Node {
|
|||
}
|
||||
}
|
||||
|
||||
func (s *Site) layoutExists(layouts ...string) bool {
|
||||
_, found := s.findFirstLayout(layouts...)
|
||||
|
||||
return found
|
||||
}
|
||||
|
||||
func (s *Site) render(d interface{}, out string, layouts ...string) (err error) {
|
||||
|
||||
layout := s.findFirstLayout(layouts...)
|
||||
if layout == "" {
|
||||
layout, found := s.findFirstLayout(layouts...)
|
||||
if found == false {
|
||||
jww.WARN.Printf("Unable to locate layout: %s\n", layouts)
|
||||
return
|
||||
}
|
||||
|
@ -634,13 +653,13 @@ func (s *Site) render(d interface{}, out string, layouts ...string) (err error)
|
|||
return s.WritePublic(out, outBuffer)
|
||||
}
|
||||
|
||||
func (s *Site) findFirstLayout(layouts ...string) (layout string) {
|
||||
for _, layout = range layouts {
|
||||
func (s *Site) findFirstLayout(layouts ...string) (string, bool) {
|
||||
for _, layout := range layouts {
|
||||
if s.Tmpl.Lookup(layout) != nil {
|
||||
return
|
||||
return layout, true
|
||||
}
|
||||
}
|
||||
return ""
|
||||
return "", false
|
||||
}
|
||||
|
||||
func (s *Site) renderThing(d interface{}, layout string, w io.Writer) error {
|
||||
|
|
|
@ -423,7 +423,7 @@ func TestOrderedPages(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
var PAGE_WITH_WEIGHTED_INDEXES_2 = []byte(`+++
|
||||
var PAGE_WITH_WEIGHTED_TAXONOMIES_2 = []byte(`+++
|
||||
tags = [ "a", "b", "c" ]
|
||||
tags_weight = 22
|
||||
categories = ["d"]
|
||||
|
@ -432,7 +432,7 @@ categories_weight = 44
|
|||
+++
|
||||
Front Matter with weighted tags and categories`)
|
||||
|
||||
var PAGE_WITH_WEIGHTED_INDEXES_1 = []byte(`+++
|
||||
var PAGE_WITH_WEIGHTED_TAXONOMIES_1 = []byte(`+++
|
||||
tags = [ "a" ]
|
||||
tags_weight = 33
|
||||
title = "bar"
|
||||
|
@ -443,7 +443,7 @@ date = 1979-05-27T07:32:00Z
|
|||
+++
|
||||
Front Matter with weighted tags and categories`)
|
||||
|
||||
var PAGE_WITH_WEIGHTED_INDEXES_3 = []byte(`+++
|
||||
var PAGE_WITH_WEIGHTED_TAXONOMIES_3 = []byte(`+++
|
||||
title = "bza"
|
||||
categories = [ "e" ]
|
||||
categories_weight = 11
|
||||
|
@ -452,21 +452,21 @@ date = 2010-05-27T07:32:00Z
|
|||
+++
|
||||
Front Matter with weighted tags and categories`)
|
||||
|
||||
func TestWeightedIndexes(t *testing.T) {
|
||||
func TestWeightedTaxonomies(t *testing.T) {
|
||||
files := make(map[string][]byte)
|
||||
target := &target.InMemoryTarget{Files: files}
|
||||
sources := []source.ByteSource{
|
||||
{"sect/doc1.md", PAGE_WITH_WEIGHTED_INDEXES_1, "sect"},
|
||||
{"sect/doc2.md", PAGE_WITH_WEIGHTED_INDEXES_2, "sect"},
|
||||
{"sect/doc3.md", PAGE_WITH_WEIGHTED_INDEXES_3, "sect"},
|
||||
{"sect/doc1.md", PAGE_WITH_WEIGHTED_TAXONOMIES_1, "sect"},
|
||||
{"sect/doc2.md", PAGE_WITH_WEIGHTED_TAXONOMIES_2, "sect"},
|
||||
{"sect/doc3.md", PAGE_WITH_WEIGHTED_TAXONOMIES_3, "sect"},
|
||||
}
|
||||
indexes := make(map[string]string)
|
||||
taxonomies := make(map[string]string)
|
||||
|
||||
indexes["tag"] = "tags"
|
||||
indexes["category"] = "categories"
|
||||
taxonomies["tag"] = "tags"
|
||||
taxonomies["category"] = "categories"
|
||||
|
||||
viper.Set("baseurl", "http://auth/bub")
|
||||
viper.Set("indexes", indexes)
|
||||
viper.Set("taxonomies", taxonomies)
|
||||
s := &Site{
|
||||
Target: target,
|
||||
Source: &source.InMemorySource{ByteSource: sources},
|
||||
|
@ -481,15 +481,15 @@ func TestWeightedIndexes(t *testing.T) {
|
|||
t.Fatalf("Unable to build site metadata: %s", err)
|
||||
}
|
||||
|
||||
if s.Indexes["tags"]["a"][0].Page.Title != "foo" {
|
||||
t.Errorf("Pages in unexpected order, 'foo' expected first, got '%v'", s.Indexes["tags"]["a"][0].Page.Title)
|
||||
if s.Taxonomies["tags"]["a"][0].Page.Title != "foo" {
|
||||
t.Errorf("Pages in unexpected order, 'foo' expected first, got '%v'", s.Taxonomies["tags"]["a"][0].Page.Title)
|
||||
}
|
||||
|
||||
if s.Indexes["categories"]["d"][0].Page.Title != "bar" {
|
||||
t.Errorf("Pages in unexpected order, 'bar' expected first, got '%v'", s.Indexes["categories"]["d"][0].Page.Title)
|
||||
if s.Taxonomies["categories"]["d"][0].Page.Title != "bar" {
|
||||
t.Errorf("Pages in unexpected order, 'bar' expected first, got '%v'", s.Taxonomies["categories"]["d"][0].Page.Title)
|
||||
}
|
||||
|
||||
if s.Indexes["categories"]["e"][0].Page.Title != "bza" {
|
||||
t.Errorf("Pages in unexpected order, 'bza' expected first, got '%v'", s.Indexes["categories"]["e"][0].Page.Title)
|
||||
if s.Taxonomies["categories"]["e"][0].Page.Title != "bza" {
|
||||
t.Errorf("Pages in unexpected order, 'bza' expected first, got '%v'", s.Taxonomies["categories"]["e"][0].Page.Title)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,8 +71,8 @@ func TestPageCount(t *testing.T) {
|
|||
t.Errorf("Unable to build site metadata: %s", err)
|
||||
}
|
||||
|
||||
if err := s.RenderLists(); err != nil {
|
||||
t.Errorf("Unable to render site lists: %s", err)
|
||||
if err := s.RenderSectionLists(); err != nil {
|
||||
t.Errorf("Unable to render section lists: %s", err)
|
||||
}
|
||||
|
||||
if err := s.RenderAliases(); err != nil {
|
||||
|
|
|
@ -20,18 +20,18 @@ import (
|
|||
)
|
||||
|
||||
/*
|
||||
* An index list is a list of all indexes and their values
|
||||
* EG. List['tags'] => TagIndex (from above)
|
||||
* An taxonomy list is a list of all taxonomies and their values
|
||||
* EG. List['tags'] => TagTaxonomy (from above)
|
||||
*/
|
||||
type IndexList map[string]Index
|
||||
type TaxonomyList map[string]Taxonomy
|
||||
|
||||
/*
|
||||
* An index is a map of keywords to a list of pages.
|
||||
* An taxonomy is a map of keywords to a list of pages.
|
||||
* For example
|
||||
* TagIndex['technology'] = WeightedPages
|
||||
* TagIndex['go'] = WeightedPages2
|
||||
* TagTaxonomy['technology'] = WeightedPages
|
||||
* TagTaxonomy['go'] = WeightedPages2
|
||||
*/
|
||||
type Index map[string]WeightedPages
|
||||
type Taxonomy map[string]WeightedPages
|
||||
|
||||
/*
|
||||
* A list of Pages with their corresponding (and relative) weight
|
||||
|
@ -44,108 +44,108 @@ type WeightedPage struct {
|
|||
}
|
||||
|
||||
/*
|
||||
* This is another representation of an Index using an array rather than a map.
|
||||
* This is another representation of an Taxonomy using an array rather than a map.
|
||||
* Important because you can't order a map.
|
||||
*/
|
||||
type OrderedIndex []OrderedIndexEntry
|
||||
type OrderedTaxonomy []OrderedTaxonomyEntry
|
||||
|
||||
/*
|
||||
* Similar to an element of an Index, but with the key embedded (as name)
|
||||
* Eg: {Name: Technology, WeightedPages: Indexedpages}
|
||||
* Similar to an element of an Taxonomy, but with the key embedded (as name)
|
||||
* Eg: {Name: Technology, WeightedPages: Taxonomyedpages}
|
||||
*/
|
||||
type OrderedIndexEntry struct {
|
||||
type OrderedTaxonomyEntry struct {
|
||||
Name string
|
||||
WeightedPages WeightedPages
|
||||
}
|
||||
|
||||
// KeyPrep... Indexes should be case insensitive. Can make it easily conditional later.
|
||||
// KeyPrep... Taxonomies should be case insensitive. Can make it easily conditional later.
|
||||
func kp(in string) string {
|
||||
return helpers.MakePath(in)
|
||||
}
|
||||
|
||||
func (i Index) Get(key string) WeightedPages { return i[kp(key)] }
|
||||
func (i Index) Count(key string) int { return len(i[kp(key)]) }
|
||||
func (i Index) Add(key string, w WeightedPage) {
|
||||
func (i Taxonomy) Get(key string) WeightedPages { return i[kp(key)] }
|
||||
func (i Taxonomy) Count(key string) int { return len(i[kp(key)]) }
|
||||
func (i Taxonomy) Add(key string, w WeightedPage) {
|
||||
key = kp(key)
|
||||
i[key] = append(i[key], w)
|
||||
}
|
||||
|
||||
// Returns an ordered index with a non defined order
|
||||
func (i Index) IndexArray() OrderedIndex {
|
||||
ies := make([]OrderedIndexEntry, len(i))
|
||||
// Returns an ordered taxonomy with a non defined order
|
||||
func (i Taxonomy) TaxonomyArray() OrderedTaxonomy {
|
||||
ies := make([]OrderedTaxonomyEntry, len(i))
|
||||
count := 0
|
||||
for k, v := range i {
|
||||
ies[count] = OrderedIndexEntry{Name: k, WeightedPages: v}
|
||||
ies[count] = OrderedTaxonomyEntry{Name: k, WeightedPages: v}
|
||||
count++
|
||||
}
|
||||
return ies
|
||||
}
|
||||
|
||||
// Returns an ordered index sorted by key name
|
||||
func (i Index) Alphabetical() OrderedIndex {
|
||||
name := func(i1, i2 *OrderedIndexEntry) bool {
|
||||
// Returns an ordered taxonomy sorted by key name
|
||||
func (i Taxonomy) Alphabetical() OrderedTaxonomy {
|
||||
name := func(i1, i2 *OrderedTaxonomyEntry) bool {
|
||||
return i1.Name < i2.Name
|
||||
}
|
||||
|
||||
ia := i.IndexArray()
|
||||
ia := i.TaxonomyArray()
|
||||
OIby(name).Sort(ia)
|
||||
return ia
|
||||
}
|
||||
|
||||
// Returns an ordered index sorted by # of pages per key
|
||||
func (i Index) ByCount() OrderedIndex {
|
||||
count := func(i1, i2 *OrderedIndexEntry) bool {
|
||||
// Returns an ordered taxonomy sorted by # of pages per key
|
||||
func (i Taxonomy) ByCount() OrderedTaxonomy {
|
||||
count := func(i1, i2 *OrderedTaxonomyEntry) bool {
|
||||
return len(i1.WeightedPages) > len(i2.WeightedPages)
|
||||
}
|
||||
|
||||
ia := i.IndexArray()
|
||||
ia := i.TaxonomyArray()
|
||||
OIby(count).Sort(ia)
|
||||
return ia
|
||||
}
|
||||
|
||||
// Helper to move the page access up a level
|
||||
func (ie OrderedIndexEntry) Pages() []*Page {
|
||||
func (ie OrderedTaxonomyEntry) Pages() []*Page {
|
||||
return ie.WeightedPages.Pages()
|
||||
}
|
||||
|
||||
func (ie OrderedIndexEntry) Count() int {
|
||||
func (ie OrderedTaxonomyEntry) Count() int {
|
||||
return len(ie.WeightedPages)
|
||||
}
|
||||
|
||||
/*
|
||||
* Implementation of a custom sorter for OrderedIndexes
|
||||
* Implementation of a custom sorter for OrderedTaxonomies
|
||||
*/
|
||||
|
||||
// A type to implement the sort interface for IndexEntries.
|
||||
type orderedIndexSorter struct {
|
||||
index OrderedIndex
|
||||
by OIby
|
||||
// A type to implement the sort interface for TaxonomyEntries.
|
||||
type orderedTaxonomySorter struct {
|
||||
taxonomy OrderedTaxonomy
|
||||
by OIby
|
||||
}
|
||||
|
||||
// Closure used in the Sort.Less method.
|
||||
type OIby func(i1, i2 *OrderedIndexEntry) bool
|
||||
type OIby func(i1, i2 *OrderedTaxonomyEntry) bool
|
||||
|
||||
func (by OIby) Sort(index OrderedIndex) {
|
||||
ps := &orderedIndexSorter{
|
||||
index: index,
|
||||
by: by, // The Sort method's receiver is the function (closure) that defines the sort order.
|
||||
func (by OIby) Sort(taxonomy OrderedTaxonomy) {
|
||||
ps := &orderedTaxonomySorter{
|
||||
taxonomy: taxonomy,
|
||||
by: by, // The Sort method's receiver is the function (closure) that defines the sort order.
|
||||
}
|
||||
sort.Sort(ps)
|
||||
}
|
||||
|
||||
// Len is part of sort.Interface.
|
||||
func (s *orderedIndexSorter) Len() int {
|
||||
return len(s.index)
|
||||
func (s *orderedTaxonomySorter) Len() int {
|
||||
return len(s.taxonomy)
|
||||
}
|
||||
|
||||
// Swap is part of sort.Interface.
|
||||
func (s *orderedIndexSorter) Swap(i, j int) {
|
||||
s.index[i], s.index[j] = s.index[j], s.index[i]
|
||||
func (s *orderedTaxonomySorter) Swap(i, j int) {
|
||||
s.taxonomy[i], s.taxonomy[j] = s.taxonomy[j], s.taxonomy[i]
|
||||
}
|
||||
|
||||
// Less is part of sort.Interface. It is implemented by calling the "by" closure in the sorter.
|
||||
func (s *orderedIndexSorter) Less(i, j int) bool {
|
||||
return s.by(&s.index[i], &s.index[j])
|
||||
func (s *orderedTaxonomySorter) Less(i, j int) bool {
|
||||
return s.by(&s.taxonomy[i], &s.taxonomy[j])
|
||||
}
|
||||
|
||||
func (wp WeightedPages) Pages() Pages {
|
18
hugolib/taxonomy_test.go
Normal file
18
hugolib/taxonomy_test.go
Normal file
|
@ -0,0 +1,18 @@
|
|||
package hugolib
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSitePossibleTaxonomies(t *testing.T) {
|
||||
site := new(Site)
|
||||
page, _ := ReadFrom(strings.NewReader(PAGE_YAML_WITH_TAXONOMIES_A), "path/to/page")
|
||||
site.Pages = append(site.Pages, page)
|
||||
taxonomies := site.possibleTaxonomies()
|
||||
if !compareStringSlice(taxonomies, []string{"tags", "categories"}) {
|
||||
if !compareStringSlice(taxonomies, []string{"categories", "tags"}) {
|
||||
t.Fatalf("possible taxonomies do not match [tags categories]. Got: %s", taxonomies)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue