mirror of
https://github.com/gohugoio/hugo.git
synced 2025-03-21 14:41:03 +00:00
Added delimit & sort template functions, tests and docs
This commit is contained in:
parent
8f6f871f53
commit
717f702e2f
3 changed files with 377 additions and 2 deletions
|
@ -74,6 +74,73 @@ e.g.
|
||||||
{{ .Content}}
|
{{ .Content}}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
||||||
|
### delimit
|
||||||
|
Loops through any array, slice or map and returns a string of all the values separated by the delimiter. There is an optional third parameter that lets you choose a different delimiter to go between the last two values.
|
||||||
|
Maps will be sorted by the keys, and only a slice of the values will be returned, keeping a consistent output order.
|
||||||
|
|
||||||
|
Works on [lists](/templates/list/), [taxonomies](/taxonomies/displaying/), [terms](/templates/terms/), [groups](/templates/list/)
|
||||||
|
|
||||||
|
e.g.
|
||||||
|
// Front matter
|
||||||
|
+++
|
||||||
|
tags: [ "tag1", "tag2", "tag3" ]
|
||||||
|
+++
|
||||||
|
|
||||||
|
// Used anywhere in a template
|
||||||
|
Tags: {{ delimit .Params.tags ", " }}
|
||||||
|
|
||||||
|
// Outputs Tags: tag1, tag2, tag3
|
||||||
|
|
||||||
|
// Example with the optional "last" parameter
|
||||||
|
Tags: {{ delimit .Params.tags ", " " and " }}
|
||||||
|
|
||||||
|
// Outputs Tags: tag1, tag2 and tag3
|
||||||
|
|
||||||
|
### sort
|
||||||
|
Sorts maps, arrays and slices, returning a sorted slice. A sorted array of map values will be returned, with the keys eliminated. There are two optional arguments, which are `sortByField` and `sortAsc`. If left blank, sort will sort by keys (for maps) in ascending order.
|
||||||
|
|
||||||
|
Works on [lists](/templates/list/), [taxonomies](/taxonomies/displaying/), [terms](/templates/terms/), [groups](/templates/list/)
|
||||||
|
|
||||||
|
e.g.
|
||||||
|
// Front matter
|
||||||
|
+++
|
||||||
|
tags: [ "tag3", "tag1", "tag2" ]
|
||||||
|
+++
|
||||||
|
|
||||||
|
// Site config
|
||||||
|
+++
|
||||||
|
[params.authors]
|
||||||
|
[params.authors.Derek]
|
||||||
|
"firstName" = "Derek"
|
||||||
|
"lastName" = "Perkins"
|
||||||
|
[params.authors.Joe]
|
||||||
|
"firstName" = "Joe"
|
||||||
|
"lastName" = "Bergevin"
|
||||||
|
[params.authors.Tanner]
|
||||||
|
"firstName" = "Tanner"
|
||||||
|
"lastName" = "Linsley"
|
||||||
|
+++
|
||||||
|
|
||||||
|
// Use default sort options - sort by key / ascending
|
||||||
|
Tags: {{ range sort .Params.tags }}{{ . }} {{ end }}
|
||||||
|
|
||||||
|
// Outputs Tags: tag1 tag2 tag3
|
||||||
|
|
||||||
|
// Sort by value / descending
|
||||||
|
Tags: {{ range sort .Params.tags "value" "desc" }}{{ . }} {{ end }}
|
||||||
|
|
||||||
|
// Outputs Tags: tag3 tag2 tag1
|
||||||
|
|
||||||
|
// Use default sort options - sort by value / descending
|
||||||
|
Authors: {{ range sort .Site.Params.authors }}{{ .firstName }} {{ end }}
|
||||||
|
|
||||||
|
// Outputs Authors: Derek Joe Tanner
|
||||||
|
|
||||||
|
// Use default sort options - sort by value / descending
|
||||||
|
Authors: {{ range sort .Site.Params.authors "lastName" "desc" }}{{ .lastName }} {{ end }}
|
||||||
|
|
||||||
|
// Outputs Authors: Perkins Linsley Bergevin
|
||||||
|
|
||||||
### in
|
### in
|
||||||
Checks if an element is in an array (or slice) and returns a boolean. The elements supported are strings, integers and floats (only float64 will match as expected). In addition, it can also check if a substring exists in a string.
|
Checks if an element is in an array (or slice) and returns a boolean. The elements supported are strings, integers and floats (only float64 will match as expected). In addition, it can also check if a substring exists in a string.
|
||||||
|
|
||||||
|
|
195
tpl/template.go
195
tpl/template.go
|
@ -29,6 +29,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
@ -100,6 +101,8 @@ func New() Template {
|
||||||
"markdownify": Markdownify,
|
"markdownify": Markdownify,
|
||||||
"first": First,
|
"first": First,
|
||||||
"where": Where,
|
"where": Where,
|
||||||
|
"delimit": Delimit,
|
||||||
|
"sort": Sort,
|
||||||
"highlight": Highlight,
|
"highlight": Highlight,
|
||||||
"add": func(a, b interface{}) (interface{}, error) { return doArithmetic(a, b, '+') },
|
"add": func(a, b interface{}) (interface{}, error) { return doArithmetic(a, b, '+') },
|
||||||
"sub": func(a, b interface{}) (interface{}, error) { return doArithmetic(a, b, '-') },
|
"sub": func(a, b interface{}) (interface{}, error) { return doArithmetic(a, b, '-') },
|
||||||
|
@ -150,6 +153,8 @@ func Lt(a, b interface{}) bool {
|
||||||
|
|
||||||
func compareGetFloat(a interface{}, b interface{}) (float64, float64) {
|
func compareGetFloat(a interface{}, b interface{}) (float64, float64) {
|
||||||
var left, right float64
|
var left, right float64
|
||||||
|
var leftStr, rightStr *string
|
||||||
|
var err error
|
||||||
av := reflect.ValueOf(a)
|
av := reflect.ValueOf(a)
|
||||||
|
|
||||||
switch av.Kind() {
|
switch av.Kind() {
|
||||||
|
@ -160,7 +165,11 @@ func compareGetFloat(a interface{}, b interface{}) (float64, float64) {
|
||||||
case reflect.Float32, reflect.Float64:
|
case reflect.Float32, reflect.Float64:
|
||||||
left = av.Float()
|
left = av.Float()
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
left, _ = strconv.ParseFloat(av.String(), 64)
|
left, err = strconv.ParseFloat(av.String(), 64)
|
||||||
|
if err != nil {
|
||||||
|
str := av.String()
|
||||||
|
leftStr = &str
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bv := reflect.ValueOf(b)
|
bv := reflect.ValueOf(b)
|
||||||
|
@ -173,7 +182,22 @@ func compareGetFloat(a interface{}, b interface{}) (float64, float64) {
|
||||||
case reflect.Float32, reflect.Float64:
|
case reflect.Float32, reflect.Float64:
|
||||||
right = bv.Float()
|
right = bv.Float()
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
right, _ = strconv.ParseFloat(bv.String(), 64)
|
right, err = strconv.ParseFloat(bv.String(), 64)
|
||||||
|
if err != nil {
|
||||||
|
str := bv.String()
|
||||||
|
rightStr = &str
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case leftStr == nil || rightStr == nil:
|
||||||
|
case *leftStr < *rightStr:
|
||||||
|
return 0, 1
|
||||||
|
case *leftStr > *rightStr:
|
||||||
|
return 1, 0
|
||||||
|
default:
|
||||||
|
return 0, 0
|
||||||
}
|
}
|
||||||
|
|
||||||
return left, right
|
return left, right
|
||||||
|
@ -377,6 +401,173 @@ func Where(seq, key, match interface{}) (interface{}, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Delimit(seq, delimiter interface{}, last ...interface{}) (template.HTML, error) {
|
||||||
|
d, err := cast.ToStringE(delimiter)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
var dLast *string
|
||||||
|
for _, l := range last {
|
||||||
|
dStr, err := cast.ToStringE(l)
|
||||||
|
if err != nil {
|
||||||
|
dLast = nil
|
||||||
|
}
|
||||||
|
dLast = &dStr
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
seqv := reflect.ValueOf(seq)
|
||||||
|
for ; seqv.Kind() == reflect.Ptr || seqv.Kind() == reflect.Interface; seqv = seqv.Elem() {
|
||||||
|
if seqv.IsNil() {
|
||||||
|
return "", errors.New("can't iterate over a nil value")
|
||||||
|
}
|
||||||
|
if seqv.Kind() == reflect.Interface && seqv.NumMethod() > 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var str string
|
||||||
|
switch seqv.Kind() {
|
||||||
|
case reflect.Map:
|
||||||
|
sortSeq, err := Sort(seq)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
seqv = reflect.ValueOf(sortSeq)
|
||||||
|
fallthrough
|
||||||
|
case reflect.Array, reflect.Slice, reflect.String:
|
||||||
|
for i := 0; i < seqv.Len(); i++ {
|
||||||
|
val := seqv.Index(i).Interface()
|
||||||
|
valStr, err := cast.ToStringE(val)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch {
|
||||||
|
case i == seqv.Len()-2 && dLast != nil:
|
||||||
|
str += valStr + *dLast
|
||||||
|
case i == seqv.Len()-1:
|
||||||
|
str += valStr
|
||||||
|
default:
|
||||||
|
str += valStr + d
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return "", errors.New("can't iterate over " + reflect.ValueOf(seq).Type().String())
|
||||||
|
}
|
||||||
|
|
||||||
|
return template.HTML(str), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Sort(seq interface{}, args ...interface{}) ([]interface{}, error) {
|
||||||
|
seqv := reflect.ValueOf(seq)
|
||||||
|
for ; seqv.Kind() == reflect.Ptr || seqv.Kind() == reflect.Interface; seqv = seqv.Elem() {
|
||||||
|
if seqv.IsNil() {
|
||||||
|
return nil, errors.New("can't iterate over a nil value")
|
||||||
|
}
|
||||||
|
if seqv.Kind() == reflect.Interface && seqv.NumMethod() > 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a list of pairs that will be used to do the sort
|
||||||
|
p := pairList{SortAsc: true}
|
||||||
|
p.Pairs = make([]pair, seqv.Len())
|
||||||
|
|
||||||
|
for i, l := range args {
|
||||||
|
dStr, err := cast.ToStringE(l)
|
||||||
|
switch {
|
||||||
|
case i == 0 && err != nil:
|
||||||
|
p.SortByField = ""
|
||||||
|
case i == 0 && err == nil:
|
||||||
|
p.SortByField = dStr
|
||||||
|
case i == 1 && err == nil && dStr == "desc":
|
||||||
|
p.SortAsc = false
|
||||||
|
case i == 1:
|
||||||
|
p.SortAsc = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var sorted []interface{}
|
||||||
|
switch seqv.Kind() {
|
||||||
|
case reflect.Array, reflect.Slice:
|
||||||
|
for i := 0; i < seqv.Len(); i++ {
|
||||||
|
p.Pairs[i].Key = reflect.ValueOf(i)
|
||||||
|
p.Pairs[i].Value = seqv.Index(i)
|
||||||
|
}
|
||||||
|
if p.SortByField == "" {
|
||||||
|
p.SortByField = "value"
|
||||||
|
}
|
||||||
|
|
||||||
|
case reflect.Map:
|
||||||
|
keys := seqv.MapKeys()
|
||||||
|
for i := 0; i < seqv.Len(); i++ {
|
||||||
|
p.Pairs[i].Key = keys[i]
|
||||||
|
p.Pairs[i].Value = seqv.MapIndex(keys[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, errors.New("can't sort " + reflect.ValueOf(seq).Type().String())
|
||||||
|
}
|
||||||
|
sorted = p.sort()
|
||||||
|
return sorted, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Credit for pair sorting method goes to Andrew Gerrand
|
||||||
|
// https://groups.google.com/forum/#!topic/golang-nuts/FT7cjmcL7gw
|
||||||
|
// A data structure to hold a key/value pair.
|
||||||
|
type pair struct {
|
||||||
|
Key reflect.Value
|
||||||
|
Value reflect.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
// A slice of pairs that implements sort.Interface to sort by Value.
|
||||||
|
type pairList struct {
|
||||||
|
Pairs []pair
|
||||||
|
SortByField string
|
||||||
|
SortAsc bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p pairList) Swap(i, j int) { p.Pairs[i], p.Pairs[j] = p.Pairs[j], p.Pairs[i] }
|
||||||
|
func (p pairList) Len() int { return len(p.Pairs) }
|
||||||
|
func (p pairList) Less(i, j int) bool {
|
||||||
|
var truth bool
|
||||||
|
switch {
|
||||||
|
case p.SortByField == "value":
|
||||||
|
iVal := p.Pairs[i].Value
|
||||||
|
jVal := p.Pairs[j].Value
|
||||||
|
truth = Lt(iVal.Interface(), jVal.Interface())
|
||||||
|
|
||||||
|
case p.SortByField != "":
|
||||||
|
if p.Pairs[i].Value.FieldByName(p.SortByField).IsValid() {
|
||||||
|
iVal := p.Pairs[i].Value.FieldByName(p.SortByField)
|
||||||
|
jVal := p.Pairs[j].Value.FieldByName(p.SortByField)
|
||||||
|
truth = Lt(iVal.Interface(), jVal.Interface())
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
iVal := p.Pairs[i].Key
|
||||||
|
jVal := p.Pairs[j].Key
|
||||||
|
truth = Lt(iVal.Interface(), jVal.Interface())
|
||||||
|
}
|
||||||
|
return truth
|
||||||
|
}
|
||||||
|
|
||||||
|
// sorts a pairList and returns a slice of sorted values
|
||||||
|
func (p pairList) sort() []interface{} {
|
||||||
|
if p.SortAsc {
|
||||||
|
sort.Sort(p)
|
||||||
|
} else {
|
||||||
|
sort.Sort(sort.Reverse(p))
|
||||||
|
}
|
||||||
|
sorted := make([]interface{}, len(p.Pairs))
|
||||||
|
for i, v := range p.Pairs {
|
||||||
|
sorted[i] = v.Value.Interface()
|
||||||
|
}
|
||||||
|
|
||||||
|
return sorted
|
||||||
|
}
|
||||||
|
|
||||||
func IsSet(a interface{}, key interface{}) bool {
|
func IsSet(a interface{}, key interface{}) bool {
|
||||||
av := reflect.ValueOf(a)
|
av := reflect.ValueOf(a)
|
||||||
kv := reflect.ValueOf(key)
|
kv := reflect.ValueOf(key)
|
||||||
|
|
|
@ -341,6 +341,123 @@ func TestWhere(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDelimit(t *testing.T) {
|
||||||
|
for i, this := range []struct {
|
||||||
|
sequence interface{}
|
||||||
|
delimiter interface{}
|
||||||
|
last interface{}
|
||||||
|
expect template.HTML
|
||||||
|
}{
|
||||||
|
{[]string{"class1", "class2", "class3"}, " ", nil, "class1 class2 class3"},
|
||||||
|
{[]int{1, 2, 3, 4, 5}, ",", nil, "1,2,3,4,5"},
|
||||||
|
{[]int{1, 2, 3, 4, 5}, ", ", nil, "1, 2, 3, 4, 5"},
|
||||||
|
{[]string{"class1", "class2", "class3"}, " ", " and ", "class1 class2 and class3"},
|
||||||
|
{[]int{1, 2, 3, 4, 5}, ",", ",", "1,2,3,4,5"},
|
||||||
|
{[]int{1, 2, 3, 4, 5}, ", ", ", and ", "1, 2, 3, 4, and 5"},
|
||||||
|
// test maps with and without sorting required
|
||||||
|
{map[string]int{"1": 10, "2": 20, "3": 30, "4": 40, "5": 50}, "--", nil, "10--20--30--40--50"},
|
||||||
|
{map[string]int{"3": 10, "2": 20, "1": 30, "4": 40, "5": 50}, "--", nil, "30--20--10--40--50"},
|
||||||
|
{map[string]string{"1": "10", "2": "20", "3": "30", "4": "40", "5": "50"}, "--", nil, "10--20--30--40--50"},
|
||||||
|
{map[string]string{"3": "10", "2": "20", "1": "30", "4": "40", "5": "50"}, "--", nil, "30--20--10--40--50"},
|
||||||
|
{map[string]string{"one": "10", "two": "20", "three": "30", "four": "40", "five": "50"}, "--", nil, "50--40--10--30--20"},
|
||||||
|
{map[int]string{1: "10", 2: "20", 3: "30", 4: "40", 5: "50"}, "--", nil, "10--20--30--40--50"},
|
||||||
|
{map[int]string{3: "10", 2: "20", 1: "30", 4: "40", 5: "50"}, "--", nil, "30--20--10--40--50"},
|
||||||
|
{map[float64]string{3.3: "10", 2.3: "20", 1.3: "30", 4.3: "40", 5.3: "50"}, "--", nil, "30--20--10--40--50"},
|
||||||
|
// test maps with a last delimiter
|
||||||
|
{map[string]int{"1": 10, "2": 20, "3": 30, "4": 40, "5": 50}, "--", "--and--", "10--20--30--40--and--50"},
|
||||||
|
{map[string]int{"3": 10, "2": 20, "1": 30, "4": 40, "5": 50}, "--", "--and--", "30--20--10--40--and--50"},
|
||||||
|
{map[string]string{"1": "10", "2": "20", "3": "30", "4": "40", "5": "50"}, "--", "--and--", "10--20--30--40--and--50"},
|
||||||
|
{map[string]string{"3": "10", "2": "20", "1": "30", "4": "40", "5": "50"}, "--", "--and--", "30--20--10--40--and--50"},
|
||||||
|
{map[string]string{"one": "10", "two": "20", "three": "30", "four": "40", "five": "50"}, "--", "--and--", "50--40--10--30--and--20"},
|
||||||
|
{map[int]string{1: "10", 2: "20", 3: "30", 4: "40", 5: "50"}, "--", "--and--", "10--20--30--40--and--50"},
|
||||||
|
{map[int]string{3: "10", 2: "20", 1: "30", 4: "40", 5: "50"}, "--", "--and--", "30--20--10--40--and--50"},
|
||||||
|
{map[float64]string{3.5: "10", 2.5: "20", 1.5: "30", 4.5: "40", 5.5: "50"}, "--", "--and--", "30--20--10--40--and--50"},
|
||||||
|
} {
|
||||||
|
var result template.HTML
|
||||||
|
var err error
|
||||||
|
if this.last == nil {
|
||||||
|
result, err = Delimit(this.sequence, this.delimiter)
|
||||||
|
} else {
|
||||||
|
result, err = Delimit(this.sequence, this.delimiter, this.last)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("[%d] failed: %s", i, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(result, this.expect) {
|
||||||
|
t.Errorf("[%d] Delimit called on sequence: %v | delimiter: `%v` | last: `%v`, got %v but expected %v", i, this.sequence, this.delimiter, this.last, result, this.expect)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSort(t *testing.T) {
|
||||||
|
type ts struct {
|
||||||
|
MyInt int
|
||||||
|
MyFloat float64
|
||||||
|
MyString string
|
||||||
|
}
|
||||||
|
for i, this := range []struct {
|
||||||
|
sequence interface{}
|
||||||
|
sortByField interface{}
|
||||||
|
sortAsc string
|
||||||
|
expect []interface{}
|
||||||
|
}{
|
||||||
|
{[]string{"class1", "class2", "class3"}, nil, "asc", []interface{}{"class1", "class2", "class3"}},
|
||||||
|
{[]string{"class3", "class1", "class2"}, nil, "asc", []interface{}{"class1", "class2", "class3"}},
|
||||||
|
{[]int{1, 2, 3, 4, 5}, nil, "asc", []interface{}{1, 2, 3, 4, 5}},
|
||||||
|
{[]int{5, 4, 3, 1, 2}, nil, "asc", []interface{}{1, 2, 3, 4, 5}},
|
||||||
|
// test map sorting by keys
|
||||||
|
{map[string]int{"1": 10, "2": 20, "3": 30, "4": 40, "5": 50}, nil, "asc", []interface{}{10, 20, 30, 40, 50}},
|
||||||
|
{map[string]int{"3": 10, "2": 20, "1": 30, "4": 40, "5": 50}, nil, "asc", []interface{}{30, 20, 10, 40, 50}},
|
||||||
|
{map[string]string{"1": "10", "2": "20", "3": "30", "4": "40", "5": "50"}, nil, "asc", []interface{}{"10", "20", "30", "40", "50"}},
|
||||||
|
{map[string]string{"3": "10", "2": "20", "1": "30", "4": "40", "5": "50"}, nil, "asc", []interface{}{"30", "20", "10", "40", "50"}},
|
||||||
|
{map[string]string{"one": "10", "two": "20", "three": "30", "four": "40", "five": "50"}, nil, "asc", []interface{}{"50", "40", "10", "30", "20"}},
|
||||||
|
{map[int]string{1: "10", 2: "20", 3: "30", 4: "40", 5: "50"}, nil, "asc", []interface{}{"10", "20", "30", "40", "50"}},
|
||||||
|
{map[int]string{3: "10", 2: "20", 1: "30", 4: "40", 5: "50"}, nil, "asc", []interface{}{"30", "20", "10", "40", "50"}},
|
||||||
|
{map[float64]string{3.3: "10", 2.3: "20", 1.3: "30", 4.3: "40", 5.3: "50"}, nil, "asc", []interface{}{"30", "20", "10", "40", "50"}},
|
||||||
|
// test map sorting by value
|
||||||
|
{map[string]int{"1": 10, "2": 20, "3": 30, "4": 40, "5": 50}, "value", "asc", []interface{}{10, 20, 30, 40, 50}},
|
||||||
|
{map[string]int{"3": 10, "2": 20, "1": 30, "4": 40, "5": 50}, "value", "asc", []interface{}{10, 20, 30, 40, 50}},
|
||||||
|
// test map sorting by field value
|
||||||
|
{
|
||||||
|
map[string]ts{"1": ts{10, 10.5, "ten"}, "2": ts{20, 20.5, "twenty"}, "3": ts{30, 30.5, "thirty"}, "4": ts{40, 40.5, "forty"}, "5": ts{50, 50.5, "fifty"}},
|
||||||
|
"MyInt",
|
||||||
|
"asc",
|
||||||
|
[]interface{}{ts{10, 10.5, "ten"}, ts{20, 20.5, "twenty"}, ts{30, 30.5, "thirty"}, ts{40, 40.5, "forty"}, ts{50, 50.5, "fifty"}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
map[string]ts{"1": ts{10, 10.5, "ten"}, "2": ts{20, 20.5, "twenty"}, "3": ts{30, 30.5, "thirty"}, "4": ts{40, 40.5, "forty"}, "5": ts{50, 50.5, "fifty"}},
|
||||||
|
"MyFloat",
|
||||||
|
"asc",
|
||||||
|
[]interface{}{ts{10, 10.5, "ten"}, ts{20, 20.5, "twenty"}, ts{30, 30.5, "thirty"}, ts{40, 40.5, "forty"}, ts{50, 50.5, "fifty"}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
map[string]ts{"1": ts{10, 10.5, "ten"}, "2": ts{20, 20.5, "twenty"}, "3": ts{30, 30.5, "thirty"}, "4": ts{40, 40.5, "forty"}, "5": ts{50, 50.5, "fifty"}},
|
||||||
|
"MyString",
|
||||||
|
"asc",
|
||||||
|
[]interface{}{ts{50, 50.5, "fifty"}, ts{40, 40.5, "forty"}, ts{10, 10.5, "ten"}, ts{30, 30.5, "thirty"}, ts{20, 20.5, "twenty"}},
|
||||||
|
},
|
||||||
|
// Test sort desc
|
||||||
|
{[]string{"class1", "class2", "class3"}, "value", "desc", []interface{}{"class3", "class2", "class1"}},
|
||||||
|
{[]string{"class3", "class1", "class2"}, "value", "desc", []interface{}{"class3", "class2", "class1"}},
|
||||||
|
} {
|
||||||
|
var result []interface{}
|
||||||
|
var err error
|
||||||
|
if this.sortByField == nil {
|
||||||
|
result, err = Sort(this.sequence)
|
||||||
|
} else {
|
||||||
|
result, err = Sort(this.sequence, this.sortByField, this.sortAsc)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("[%d] failed: %s", i, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(result, this.expect) {
|
||||||
|
t.Errorf("[%d] Sort called on sequence: %v | sortByField: `%v` | got %v but expected %v", i, this.sequence, this.sortByField, result, this.expect)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestMarkdownify(t *testing.T) {
|
func TestMarkdownify(t *testing.T) {
|
||||||
|
|
||||||
result := Markdownify("Hello **World!**")
|
result := Markdownify("Hello **World!**")
|
||||||
|
|
Loading…
Reference in a new issue