github.com/graemephi/kahugo@v0.62.3-0.20211121071557-d78c0423784d/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  }