github.com/kovansky/hugo@v0.92.3-0.20220224232819-63076e4ff19f/hugolib/taxonomy.go (about) 1 // Copyright 2019 The Hugo Authors. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package hugolib 15 16 import ( 17 "fmt" 18 "sort" 19 20 "github.com/gohugoio/hugo/compare" 21 22 "github.com/gohugoio/hugo/resources/page" 23 ) 24 25 // The TaxonomyList is a list of all taxonomies and their values 26 // e.g. List['tags'] => TagTaxonomy (from above) 27 type TaxonomyList map[string]Taxonomy 28 29 func (tl TaxonomyList) String() string { 30 return fmt.Sprintf("TaxonomyList(%d)", len(tl)) 31 } 32 33 // A Taxonomy is a map of keywords to a list of pages. 34 // For example 35 // TagTaxonomy['technology'] = page.WeightedPages 36 // TagTaxonomy['go'] = page.WeightedPages 37 type Taxonomy map[string]page.WeightedPages 38 39 // OrderedTaxonomy is another representation of an Taxonomy using an array rather than a map. 40 // Important because you can't order a map. 41 type OrderedTaxonomy []OrderedTaxonomyEntry 42 43 // OrderedTaxonomyEntry is similar to an element of a Taxonomy, but with the key embedded (as name) 44 // e.g: {Name: Technology, page.WeightedPages: TaxonomyPages} 45 type OrderedTaxonomyEntry struct { 46 Name string 47 page.WeightedPages 48 } 49 50 // Get the weighted pages for the given key. 51 func (i Taxonomy) Get(key string) page.WeightedPages { 52 return i[key] 53 } 54 55 // Count the weighted pages for the given key. 56 func (i Taxonomy) Count(key string) int { return len(i[key]) } 57 58 func (i Taxonomy) add(key string, w page.WeightedPage) { 59 i[key] = append(i[key], w) 60 } 61 62 // TaxonomyArray returns an ordered taxonomy with a non defined order. 63 func (i Taxonomy) TaxonomyArray() OrderedTaxonomy { 64 ies := make([]OrderedTaxonomyEntry, len(i)) 65 count := 0 66 for k, v := range i { 67 ies[count] = OrderedTaxonomyEntry{Name: k, WeightedPages: v} 68 count++ 69 } 70 return ies 71 } 72 73 // Alphabetical returns an ordered taxonomy sorted by key name. 74 func (i Taxonomy) Alphabetical() OrderedTaxonomy { 75 name := func(i1, i2 *OrderedTaxonomyEntry) bool { 76 return compare.LessStrings(i1.Name, i2.Name) 77 } 78 79 ia := i.TaxonomyArray() 80 oiBy(name).Sort(ia) 81 return ia 82 } 83 84 // ByCount returns an ordered taxonomy sorted by # of pages per key. 85 // If taxonomies have the same # of pages, sort them alphabetical 86 func (i Taxonomy) ByCount() OrderedTaxonomy { 87 count := func(i1, i2 *OrderedTaxonomyEntry) bool { 88 li1 := len(i1.WeightedPages) 89 li2 := len(i2.WeightedPages) 90 91 if li1 == li2 { 92 return compare.LessStrings(i1.Name, i2.Name) 93 } 94 return li1 > li2 95 } 96 97 ia := i.TaxonomyArray() 98 oiBy(count).Sort(ia) 99 return ia 100 } 101 102 // Pages returns the Pages for this taxonomy. 103 func (ie OrderedTaxonomyEntry) Pages() page.Pages { 104 return ie.WeightedPages.Pages() 105 } 106 107 // Count returns the count the pages in this taxonomy. 108 func (ie OrderedTaxonomyEntry) Count() int { 109 return len(ie.WeightedPages) 110 } 111 112 // Term returns the name given to this taxonomy. 113 func (ie OrderedTaxonomyEntry) Term() string { 114 return ie.Name 115 } 116 117 // Reverse reverses the order of the entries in this taxonomy. 118 func (t OrderedTaxonomy) Reverse() OrderedTaxonomy { 119 for i, j := 0, len(t)-1; i < j; i, j = i+1, j-1 { 120 t[i], t[j] = t[j], t[i] 121 } 122 123 return t 124 } 125 126 // A type to implement the sort interface for TaxonomyEntries. 127 type orderedTaxonomySorter struct { 128 taxonomy OrderedTaxonomy 129 by oiBy 130 } 131 132 // Closure used in the Sort.Less method. 133 type oiBy func(i1, i2 *OrderedTaxonomyEntry) bool 134 135 func (by oiBy) Sort(taxonomy OrderedTaxonomy) { 136 ps := &orderedTaxonomySorter{ 137 taxonomy: taxonomy, 138 by: by, // The Sort method's receiver is the function (closure) that defines the sort order. 139 } 140 sort.Stable(ps) 141 } 142 143 // Len is part of sort.Interface. 144 func (s *orderedTaxonomySorter) Len() int { 145 return len(s.taxonomy) 146 } 147 148 // Swap is part of sort.Interface. 149 func (s *orderedTaxonomySorter) Swap(i, j int) { 150 s.taxonomy[i], s.taxonomy[j] = s.taxonomy[j], s.taxonomy[i] 151 } 152 153 // Less is part of sort.Interface. It is implemented by calling the "by" closure in the sorter. 154 func (s *orderedTaxonomySorter) Less(i, j int) bool { 155 return s.by(&s.taxonomy[i], &s.taxonomy[j]) 156 }