hugolib: Add ability to sort by frontmatter parameters

This commit is contained in:
John Feminella 2017-02-10 08:01:25 -05:00 committed by Bjørn Erik Pedersen
parent 2618cfbeaa
commit 298ebc37c2
3 changed files with 71 additions and 0 deletions

View file

@ -237,6 +237,18 @@ your list templates:
</li> </li>
{{ end }} {{ end }}
### Order by Parameter
Order based on the specified frontmatter parameter. Pages without that
parameter will use the site's `.Site.Params` default. If the parameter is not
found at all in some entries, those entries will appear together at the end
of the ordering.
The below example sorts a list of posts by their rating.
{{ range (.Data.Pages.ByParam "rating") }}
<!-- ... -->
{{ end }}
### Reverse Order ### Reverse Order
Can be applied to any of the above. Using Date for an example. Can be applied to any of the above. Using Date for an example.

View file

@ -15,6 +15,8 @@ package hugolib
import ( import (
"sort" "sort"
"github.com/spf13/cast"
) )
var spc = newPageCache() var spc = newPageCache()
@ -275,3 +277,28 @@ func (p Pages) Reverse() Pages {
return pages return pages
} }
func (p Pages) ByParam(paramsKey interface{}) Pages {
paramsKeyStr := cast.ToString(paramsKey)
key := "pageSort.ByParam." + paramsKeyStr
paramsKeyComparator := func(p1, p2 *Page) bool {
v1, _ := p1.Param(paramsKeyStr)
v2, _ := p2.Param(paramsKeyStr)
s1 := cast.ToString(v1)
s2 := cast.ToString(v2)
// Sort nils last.
if s1 == "" {
return false
} else if s2 == "" {
return true
}
return s1 < s2
}
pages, _ := spc.get(key, p, pageBy(paramsKeyComparator).Sort)
return pages
}

View file

@ -20,6 +20,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/spf13/cast"
"github.com/spf13/hugo/helpers" "github.com/spf13/hugo/helpers"
"github.com/spf13/hugo/source" "github.com/spf13/hugo/source"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -113,6 +114,34 @@ func TestPageSortReverse(t *testing.T) {
assert.True(t, probablyEqualPages(p2, p1.Reverse())) assert.True(t, probablyEqualPages(p2, p1.Reverse()))
} }
func TestPageSortByParam(t *testing.T) {
var k interface{} = "arbitrary"
unsorted := createSortTestPages(10)
delete(unsorted[9].Params, cast.ToString(k))
firstSetValue, _ := unsorted[0].Param(k)
secondSetValue, _ := unsorted[1].Param(k)
lastSetValue, _ := unsorted[8].Param(k)
unsetValue, _ := unsorted[9].Param(k)
assert.Equal(t, "xyz100", firstSetValue)
assert.Equal(t, "xyz99", secondSetValue)
assert.Equal(t, "xyz92", lastSetValue)
assert.Equal(t, nil, unsetValue)
sorted := unsorted.ByParam("arbitrary")
firstSetSortedValue, _ := sorted[0].Param(k)
secondSetSortedValue, _ := sorted[1].Param(k)
lastSetSortedValue, _ := sorted[8].Param(k)
unsetSortedValue, _ := sorted[9].Param(k)
assert.Equal(t, firstSetValue, firstSetSortedValue)
assert.Equal(t, secondSetValue, lastSetSortedValue)
assert.Equal(t, lastSetValue, secondSetSortedValue)
assert.Equal(t, unsetValue, unsetSortedValue)
}
func BenchmarkSortByWeightAndReverse(b *testing.B) { func BenchmarkSortByWeightAndReverse(b *testing.B) {
p := createSortTestPages(300) p := createSortTestPages(300)
@ -154,6 +183,9 @@ func createSortTestPages(num int) Pages {
}, },
Site: &info, Site: &info,
Source: Source{File: *source.NewFile(filepath.FromSlash(fmt.Sprintf("/x/y/p%d.md", i)))}, Source: Source{File: *source.NewFile(filepath.FromSlash(fmt.Sprintf("/x/y/p%d.md", i)))},
Params: map[string]interface{}{
"arbitrary": "xyz" + fmt.Sprintf("%v", 100-i),
},
} }
w := 5 w := 5