From 597e418cb02883418f2cebb41400e8e61413f651 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Pedersen?= Date: Wed, 2 Jan 2019 12:33:26 +0100 Subject: Make Page an interface The main motivation of this commit is to add a `page.Page` interface to replace the very file-oriented `hugolib.Page` struct. This is all a preparation step for issue #5074, "pages from other data sources". But this also fixes a set of annoying limitations, especially related to custom output formats, and shortcodes. Most notable changes: * The inner content of shortcodes using the `{{%` as the outer-most delimiter will now be sent to the content renderer, e.g. Blackfriday. This means that any markdown will partake in the global ToC and footnote context etc. * The Custom Output formats are now "fully virtualized". This removes many of the current limitations. * The taxonomy list type now has a reference to the `Page` object. This improves the taxonomy template `.Title` situation and make common template constructs much simpler. See #5074 Fixes #5763 Fixes #5758 Fixes #5090 Fixes #5204 Fixes #4695 Fixes #5607 Fixes #5707 Fixes #5719 Fixes #3113 Fixes #5706 Fixes #5767 Fixes #5723 Fixes #5769 Fixes #5770 Fixes #5771 Fixes #5759 Fixes #5776 Fixes #5777 Fixes #5778 --- related/inverted_index.go | 25 ++++++++++++++++--------- related/inverted_index_test.go | 42 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 53 insertions(+), 14 deletions(-) (limited to 'related') diff --git a/related/inverted_index.go b/related/inverted_index.go index 309eb4097..fda6b9222 100644 --- a/related/inverted_index.go +++ b/related/inverted_index.go @@ -1,4 +1,4 @@ -// Copyright 2017-present The Hugo Authors. All rights reserved. +// Copyright 2019 The Hugo Authors. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -106,11 +106,15 @@ type IndexConfig struct { // Document is the interface an indexable document in Hugo must fulfill. type Document interface { - // SearchKeywords returns a list of keywords for the given index config. - SearchKeywords(cfg IndexConfig) ([]Keyword, error) + // RelatedKeywords returns a list of keywords for the given index config. + RelatedKeywords(cfg IndexConfig) ([]Keyword, error) // When this document was or will be published. - PubDate() time.Time + PublishDate() time.Time + + // Name is used as an tiebreaker if both Weight and PublishDate are + // the same. + Name() string } // InvertedIndex holds an inverted index, also sometimes named posting list, which @@ -164,7 +168,7 @@ func (idx *InvertedIndex) Add(docs ...Document) error { for _, doc := range docs { var words []Keyword - words, err = doc.SearchKeywords(config) + words, err = doc.RelatedKeywords(config) if err != nil { continue } @@ -211,7 +215,10 @@ func (r ranks) Len() int { return len(r) } func (r ranks) Swap(i, j int) { r[i], r[j] = r[j], r[i] } func (r ranks) Less(i, j int) bool { if r[i].Weight == r[j].Weight { - return r[i].Doc.PubDate().After(r[j].Doc.PubDate()) + if r[i].Doc.PublishDate() == r[j].Doc.PublishDate() { + return r[i].Doc.Name() < r[j].Doc.Name() + } + return r[i].Doc.PublishDate().After(r[j].Doc.PublishDate()) } return r[i].Weight > r[j].Weight } @@ -241,7 +248,7 @@ func (idx *InvertedIndex) SearchDoc(doc Document, indices ...string) ([]Document } for _, cfg := range configs { - keywords, err := doc.SearchKeywords(cfg) + keywords, err := doc.RelatedKeywords(cfg) if err != nil { return nil, err } @@ -250,7 +257,7 @@ func (idx *InvertedIndex) SearchDoc(doc Document, indices ...string) ([]Document } - return idx.searchDate(doc.PubDate(), q...) + return idx.searchDate(doc.PublishDate(), q...) } // ToKeywords returns a Keyword slice of the given input. @@ -344,7 +351,7 @@ func (idx *InvertedIndex) searchDate(upperDate time.Time, query ...queryElement) for _, doc := range docs { if applyDateFilter { // Exclude newer than the limit given - if doc.PubDate().After(upperDate) { + if doc.PublishDate().After(upperDate) { continue } } diff --git a/related/inverted_index_test.go b/related/inverted_index_test.go index 2e6b90bbf..4ef27875d 100644 --- a/related/inverted_index_test.go +++ b/related/inverted_index_test.go @@ -1,4 +1,4 @@ -// Copyright 2017-present The Hugo Authors. All rights reserved. +// Copyright 2019 The Hugo Authors. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -25,6 +25,7 @@ import ( type testDoc struct { keywords map[string][]Keyword date time.Time + name string } func (d *testDoc) String() string { @@ -39,11 +40,19 @@ func (d *testDoc) String() string { return s } +func (d *testDoc) Name() string { + return d.name +} + func newTestDoc(name string, keywords ...string) *testDoc { + time.Sleep(1 * time.Millisecond) + return newTestDocWithDate(name, time.Now(), keywords...) +} + +func newTestDocWithDate(name string, date time.Time, keywords ...string) *testDoc { km := make(map[string][]Keyword) - time.Sleep(1 * time.Millisecond) - kw := &testDoc{keywords: km, date: time.Now()} + kw := &testDoc{keywords: km, date: date} kw.addKeywords(name, keywords...) return kw @@ -68,11 +77,11 @@ func createTestKeywords(name string, keywords ...string) map[string][]string { } } -func (d *testDoc) SearchKeywords(cfg IndexConfig) ([]Keyword, error) { +func (d *testDoc) RelatedKeywords(cfg IndexConfig) ([]Keyword, error) { return d.keywords[cfg.Name], nil } -func (d *testDoc) PubDate() time.Time { +func (d *testDoc) PublishDate() time.Time { return d.date } @@ -167,6 +176,29 @@ func TestSearch(t *testing.T) { assert.Equal(docs[3], m[0]) }) + t.Run("searchdoc-keywords-same-date", func(t *testing.T) { + assert := require.New(t) + idx := NewInvertedIndex(config) + + date := time.Now() + + doc := newTestDocWithDate("keywords", date, "a", "b") + doc.name = "thedoc" + + for i := 0; i < 10; i++ { + docc := *doc + docc.name = fmt.Sprintf("doc%d", i) + idx.Add(&docc) + } + + m, err := idx.SearchDoc(doc, "keywords") + assert.NoError(err) + assert.Len(m, 10) + for i := 0; i < 10; i++ { + assert.Equal(fmt.Sprintf("doc%d", i), m[i].Name()) + } + }) + } func BenchmarkRelatedNewIndex(b *testing.B) { -- cgit v1.2.3