1
0
mirror of https://github.com/danog/gojekyll.git synced 2025-01-23 00:51:16 +01:00

Add group_by tag

This commit is contained in:
Oliver Steele 2017-06-30 12:21:55 -04:00
parent 5100dc2fb3
commit 564ada3cab
2 changed files with 57 additions and 23 deletions

View File

@ -4,6 +4,7 @@ import (
"bytes"
"encoding/json"
"encoding/xml"
"fmt"
"reflect"
"regexp"
"strings"
@ -15,7 +16,7 @@ import (
)
func (e *Wrapper) addJekyllFilters() {
// arrays
// array filters
e.engine.DefineFilter("array_to_sentence_string", arrayToSentenceStringFilter)
// TODO neither Liquid nor Jekyll docs this, but it appears to be present
e.engine.DefineFilter("filter", func(values []map[string]interface{}, key string) []interface{} {
@ -27,6 +28,7 @@ func (e *Wrapper) addJekyllFilters() {
}
return out
})
e.engine.DefineFilter("group_by", groupByFilter)
// sort overrides the Liquid filter with one that takes parameters
e.engine.DefineFilter("sort", sortFilter)
e.engine.DefineFilter("where", whereFilter) // TODO test case
@ -102,14 +104,14 @@ func (e *Wrapper) addJekyllFilters() {
})
}
func arrayToSentenceStringFilter(value []string, conjunction interface{}) string {
func arrayToSentenceStringFilter(array []string, conjunction interface{}) string {
conj, ok := conjunction.(string)
if !ok {
conj = "and "
}
rt := reflect.ValueOf(value)
rt := reflect.ValueOf(array)
ar := make([]string, rt.Len())
for i, v := range value {
for i, v := range array {
ar[i] = v
if i == rt.Len()-1 {
ar[i] = conj + v
@ -118,13 +120,44 @@ func arrayToSentenceStringFilter(value []string, conjunction interface{}) string
return strings.Join(ar, ", ")
}
func sortFilter(in []interface{}, key interface{}, nilFirst interface{}) []interface{} {
func groupByFilter(array []map[string]interface{}, property string) []map[string]interface{} {
rt := reflect.ValueOf(array)
if rt.Kind() != reflect.Array && rt.Kind() != reflect.Slice {
return nil
}
groups := map[interface{}][]interface{}{}
for i := 0; i < rt.Len(); i++ {
item := rt.Index(i)
if item.Kind() == reflect.Map && item.Type().Key().Kind() == reflect.String {
attr := item.MapIndex(reflect.ValueOf(property))
// fmt.Println("invalid", item)
if attr.IsValid() {
key := attr.Interface()
group, found := groups[key]
// fmt.Println("found", attr)
if found {
group = append(group, groups[key])
} else {
group = []interface{}{item}
}
groups[key] = group
}
}
}
out := []map[string]interface{}{}
for k, v := range groups {
out = append(out, map[string]interface{}{"name": k, "items": v})
}
return out
}
func sortFilter(array []interface{}, key interface{}, nilFirst interface{}) []interface{} {
nf, ok := nilFirst.(bool)
if !ok {
nf = true
}
out := make([]interface{}, len(in))
copy(out, in)
out := make([]interface{}, len(array))
copy(out, array)
if key == nil {
generics.Sort(out)
} else {
@ -133,12 +166,10 @@ func sortFilter(in []interface{}, key interface{}, nilFirst interface{}) []inter
return out
}
func whereExpFilter(in []interface{}, name string, expr expressions.Closure) ([]interface{}, error) {
rt := reflect.ValueOf(in)
switch rt.Kind() {
case reflect.Array, reflect.Slice:
default:
return in, nil
func whereExpFilter(array []interface{}, name string, expr expressions.Closure) ([]interface{}, error) {
rt := reflect.ValueOf(array)
if rt.Kind() != reflect.Array && rt.Kind() != reflect.Slice {
return nil, nil
}
out := []interface{}{}
for i := 0; i < rt.Len(); i++ {
@ -154,11 +185,9 @@ func whereExpFilter(in []interface{}, name string, expr expressions.Closure) ([]
return out, nil
}
func whereFilter(in []map[string]interface{}, key string, value interface{}) []interface{} {
rt := reflect.ValueOf(in)
switch rt.Kind() {
case reflect.Array, reflect.Slice:
default:
func whereFilter(array []map[string]interface{}, key string, value interface{}) []interface{} {
rt := reflect.ValueOf(array)
if rt.Kind() != reflect.Array && rt.Kind() != reflect.Slice {
return nil
}
out := []interface{}{}
@ -166,7 +195,7 @@ func whereFilter(in []map[string]interface{}, key string, value interface{}) []i
item := rt.Index(i)
if item.Kind() == reflect.Map && item.Type().Key().Kind() == reflect.String {
attr := item.MapIndex(reflect.ValueOf(key))
if attr.IsValid() && (value == nil || attr.Interface() == value) {
if attr.IsValid() && fmt.Sprint(attr) == value {
out = append(out, item.Interface())
}
}

View File

@ -28,7 +28,11 @@ var filterTests = []struct{ in, expected string }{
{`{{ site.pages | sort: "weight", true | map: "name" | join }}`, "b, a, d, c"},
{`{{ site.pages | sort: "weight", false | map: "name" | join }}`, "a, d, c, b"},
{`{{ site.members | where: "graduation_year", "2014" | map: "name" | join }}`, "yes"},
{`{{ site.members | where: "graduation_year", "2014" | map: "name" }}`, "Alan"},
{`{{ site.members | where_exp: "item", "item.graduation_year == 2014" | map: "name" }}`, "Alan"},
{`{{ site.members | where_exp: "item", "item.graduation_year < 2014" | map: "name" }}`, "Alonzo"},
{`{{ site.members | where_exp: "item", "item.name contains 'Al'" | map: "name" | join }}`, "Alonzo, Alan"},
{`{{ site.members | group_by: "graduation_year" | map: "name" | sort | join }}`, "2013, 2014, 2015"},
{`{{ page.tags | push: 'Spokane' | join }}`, "Seattle, Tacoma, Spokane"},
// {`{{ page.tags | pop }}`, "Seattle"},
@ -63,9 +67,10 @@ var filterTestScope = map[string]interface{}{
},
"site": map[string]interface{}{
"members": []map[string]interface{}{
{"name": "yes", "graduation_year": "2014"},
{"name": "no", "graduation_year": "2015"},
{"name": "no"},
{"name": "Alonzo", "graduation_year": 2013},
{"name": "Alan", "graduation_year": 2014},
{"name": "Moses", "graduation_year": 2015},
{"name": "Haskell"},
},
"pages": []map[string]interface{}{
{"name": "a", "weight": 10},