github.com/shohhei1126/hugo@v0.42.2-0.20180623210752-3d5928889ad7/tpl/collections/collections.go (about)

     1  // Copyright 2017 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 collections
    15  
    16  import (
    17  	"errors"
    18  	"fmt"
    19  	"html/template"
    20  	"math/rand"
    21  	"net/url"
    22  	"reflect"
    23  	"strings"
    24  	"time"
    25  
    26  	"github.com/gohugoio/hugo/common/types"
    27  	"github.com/gohugoio/hugo/deps"
    28  	"github.com/gohugoio/hugo/helpers"
    29  	"github.com/spf13/cast"
    30  )
    31  
    32  func init() {
    33  	rand.Seed(time.Now().UTC().UnixNano())
    34  }
    35  
    36  // New returns a new instance of the collections-namespaced template functions.
    37  func New(deps *deps.Deps) *Namespace {
    38  	return &Namespace{
    39  		deps: deps,
    40  	}
    41  }
    42  
    43  // Namespace provides template functions for the "collections" namespace.
    44  type Namespace struct {
    45  	deps *deps.Deps
    46  }
    47  
    48  // After returns all the items after the first N in a rangeable list.
    49  func (ns *Namespace) After(index interface{}, seq interface{}) (interface{}, error) {
    50  	if index == nil || seq == nil {
    51  		return nil, errors.New("both limit and seq must be provided")
    52  	}
    53  
    54  	indexv, err := cast.ToIntE(index)
    55  	if err != nil {
    56  		return nil, err
    57  	}
    58  
    59  	if indexv < 1 {
    60  		return nil, errors.New("can't return negative/empty count of items from sequence")
    61  	}
    62  
    63  	seqv := reflect.ValueOf(seq)
    64  	seqv, isNil := indirect(seqv)
    65  	if isNil {
    66  		return nil, errors.New("can't iterate over a nil value")
    67  	}
    68  
    69  	switch seqv.Kind() {
    70  	case reflect.Array, reflect.Slice, reflect.String:
    71  		// okay
    72  	default:
    73  		return nil, errors.New("can't iterate over " + reflect.ValueOf(seq).Type().String())
    74  	}
    75  
    76  	if indexv >= seqv.Len() {
    77  		return nil, errors.New("no items left")
    78  	}
    79  
    80  	return seqv.Slice(indexv, seqv.Len()).Interface(), nil
    81  }
    82  
    83  // Delimit takes a given sequence and returns a delimited HTML string.
    84  // If last is passed to the function, it will be used as the final delimiter.
    85  func (ns *Namespace) Delimit(seq, delimiter interface{}, last ...interface{}) (template.HTML, error) {
    86  	d, err := cast.ToStringE(delimiter)
    87  	if err != nil {
    88  		return "", err
    89  	}
    90  
    91  	var dLast *string
    92  	if len(last) > 0 {
    93  		l := last[0]
    94  		dStr, err := cast.ToStringE(l)
    95  		if err != nil {
    96  			dLast = nil
    97  		}
    98  		dLast = &dStr
    99  	}
   100  
   101  	seqv := reflect.ValueOf(seq)
   102  	seqv, isNil := indirect(seqv)
   103  	if isNil {
   104  		return "", errors.New("can't iterate over a nil value")
   105  	}
   106  
   107  	var str string
   108  	switch seqv.Kind() {
   109  	case reflect.Map:
   110  		sortSeq, err := ns.Sort(seq)
   111  		if err != nil {
   112  			return "", err
   113  		}
   114  		seqv = reflect.ValueOf(sortSeq)
   115  		fallthrough
   116  	case reflect.Array, reflect.Slice, reflect.String:
   117  		for i := 0; i < seqv.Len(); i++ {
   118  			val := seqv.Index(i).Interface()
   119  			valStr, err := cast.ToStringE(val)
   120  			if err != nil {
   121  				continue
   122  			}
   123  			switch {
   124  			case i == seqv.Len()-2 && dLast != nil:
   125  				str += valStr + *dLast
   126  			case i == seqv.Len()-1:
   127  				str += valStr
   128  			default:
   129  				str += valStr + d
   130  			}
   131  		}
   132  
   133  	default:
   134  		return "", fmt.Errorf("can't iterate over %v", seq)
   135  	}
   136  
   137  	return template.HTML(str), nil
   138  }
   139  
   140  // Dictionary creates a map[string]interface{} from the given parameters by
   141  // walking the parameters and treating them as key-value pairs.  The number
   142  // of parameters must be even.
   143  func (ns *Namespace) Dictionary(values ...interface{}) (map[string]interface{}, error) {
   144  	if len(values)%2 != 0 {
   145  		return nil, errors.New("invalid dictionary call")
   146  	}
   147  
   148  	dict := make(map[string]interface{}, len(values)/2)
   149  
   150  	for i := 0; i < len(values); i += 2 {
   151  		key, ok := values[i].(string)
   152  		if !ok {
   153  			return nil, errors.New("dictionary keys must be strings")
   154  		}
   155  		dict[key] = values[i+1]
   156  	}
   157  
   158  	return dict, nil
   159  }
   160  
   161  // EchoParam returns a given value if it is set; otherwise, it returns an
   162  // empty string.
   163  func (ns *Namespace) EchoParam(a, key interface{}) interface{} {
   164  	av, isNil := indirect(reflect.ValueOf(a))
   165  	if isNil {
   166  		return ""
   167  	}
   168  
   169  	var avv reflect.Value
   170  	switch av.Kind() {
   171  	case reflect.Array, reflect.Slice:
   172  		index, ok := key.(int)
   173  		if ok && av.Len() > index {
   174  			avv = av.Index(index)
   175  		}
   176  	case reflect.Map:
   177  		kv := reflect.ValueOf(key)
   178  		if kv.Type().AssignableTo(av.Type().Key()) {
   179  			avv = av.MapIndex(kv)
   180  		}
   181  	}
   182  
   183  	avv, isNil = indirect(avv)
   184  
   185  	if isNil {
   186  		return ""
   187  	}
   188  
   189  	if avv.IsValid() {
   190  		switch avv.Kind() {
   191  		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   192  			return avv.Int()
   193  		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
   194  			return avv.Uint()
   195  		case reflect.Float32, reflect.Float64:
   196  			return avv.Float()
   197  		case reflect.String:
   198  			return avv.String()
   199  		}
   200  	}
   201  
   202  	return ""
   203  }
   204  
   205  // First returns the first N items in a rangeable list.
   206  func (ns *Namespace) First(limit interface{}, seq interface{}) (interface{}, error) {
   207  	if limit == nil || seq == nil {
   208  		return nil, errors.New("both limit and seq must be provided")
   209  	}
   210  
   211  	limitv, err := cast.ToIntE(limit)
   212  	if err != nil {
   213  		return nil, err
   214  	}
   215  
   216  	if limitv < 1 {
   217  		return nil, errors.New("can't return negative/empty count of items from sequence")
   218  	}
   219  
   220  	seqv := reflect.ValueOf(seq)
   221  	seqv, isNil := indirect(seqv)
   222  	if isNil {
   223  		return nil, errors.New("can't iterate over a nil value")
   224  	}
   225  
   226  	switch seqv.Kind() {
   227  	case reflect.Array, reflect.Slice, reflect.String:
   228  		// okay
   229  	default:
   230  		return nil, errors.New("can't iterate over " + reflect.ValueOf(seq).Type().String())
   231  	}
   232  
   233  	if limitv > seqv.Len() {
   234  		limitv = seqv.Len()
   235  	}
   236  
   237  	return seqv.Slice(0, limitv).Interface(), nil
   238  }
   239  
   240  // In returns whether v is in the set l.  l may be an array or slice.
   241  func (ns *Namespace) In(l interface{}, v interface{}) bool {
   242  	if l == nil || v == nil {
   243  		return false
   244  	}
   245  
   246  	lv := reflect.ValueOf(l)
   247  	vv := reflect.ValueOf(v)
   248  
   249  	switch lv.Kind() {
   250  	case reflect.Array, reflect.Slice:
   251  		for i := 0; i < lv.Len(); i++ {
   252  			lvv := lv.Index(i)
   253  			lvv, isNil := indirect(lvv)
   254  			if isNil {
   255  				continue
   256  			}
   257  			switch lvv.Kind() {
   258  			case reflect.String:
   259  				if vv.Type() == lvv.Type() && vv.String() == lvv.String() {
   260  					return true
   261  				}
   262  			default:
   263  				if isNumber(vv.Kind()) && isNumber(lvv.Kind()) {
   264  					f1, err1 := numberToFloat(vv)
   265  					f2, err2 := numberToFloat(lvv)
   266  					if err1 == nil && err2 == nil && f1 == f2 {
   267  						return true
   268  					}
   269  				}
   270  			}
   271  		}
   272  	case reflect.String:
   273  		if vv.Type() == lv.Type() && strings.Contains(lv.String(), vv.String()) {
   274  			return true
   275  		}
   276  	}
   277  	return false
   278  }
   279  
   280  // Intersect returns the common elements in the given sets, l1 and l2.  l1 and
   281  // l2 must be of the same type and may be either arrays or slices.
   282  func (ns *Namespace) Intersect(l1, l2 interface{}) (interface{}, error) {
   283  	if l1 == nil || l2 == nil {
   284  		return make([]interface{}, 0), nil
   285  	}
   286  
   287  	var ins *intersector
   288  
   289  	l1v := reflect.ValueOf(l1)
   290  	l2v := reflect.ValueOf(l2)
   291  
   292  	switch l1v.Kind() {
   293  	case reflect.Array, reflect.Slice:
   294  		ins = &intersector{r: reflect.MakeSlice(l1v.Type(), 0, 0), seen: make(map[interface{}]bool)}
   295  		switch l2v.Kind() {
   296  		case reflect.Array, reflect.Slice:
   297  			for i := 0; i < l1v.Len(); i++ {
   298  				l1vv := l1v.Index(i)
   299  				for j := 0; j < l2v.Len(); j++ {
   300  					l2vv := l2v.Index(j)
   301  					ins.handleValuePair(l1vv, l2vv)
   302  				}
   303  			}
   304  			return ins.r.Interface(), nil
   305  		default:
   306  			return nil, errors.New("can't iterate over " + reflect.ValueOf(l2).Type().String())
   307  		}
   308  	default:
   309  		return nil, errors.New("can't iterate over " + reflect.ValueOf(l1).Type().String())
   310  	}
   311  }
   312  
   313  // IsSet returns whether a given array, channel, slice, or map has a key
   314  // defined.
   315  func (ns *Namespace) IsSet(a interface{}, key interface{}) (bool, error) {
   316  	av := reflect.ValueOf(a)
   317  	kv := reflect.ValueOf(key)
   318  
   319  	switch av.Kind() {
   320  	case reflect.Array, reflect.Chan, reflect.Slice:
   321  		if int64(av.Len()) > kv.Int() {
   322  			return true, nil
   323  		}
   324  	case reflect.Map:
   325  		if kv.Type() == av.Type().Key() {
   326  			return av.MapIndex(kv).IsValid(), nil
   327  		}
   328  	default:
   329  		helpers.DistinctFeedbackLog.Printf("WARNING: calling IsSet with unsupported type %q (%T) will always return false.\n", av.Kind(), a)
   330  	}
   331  
   332  	return false, nil
   333  }
   334  
   335  // Last returns the last N items in a rangeable list.
   336  func (ns *Namespace) Last(limit interface{}, seq interface{}) (interface{}, error) {
   337  	if limit == nil || seq == nil {
   338  		return nil, errors.New("both limit and seq must be provided")
   339  	}
   340  
   341  	limitv, err := cast.ToIntE(limit)
   342  	if err != nil {
   343  		return nil, err
   344  	}
   345  
   346  	if limitv < 1 {
   347  		return nil, errors.New("can't return negative/empty count of items from sequence")
   348  	}
   349  
   350  	seqv := reflect.ValueOf(seq)
   351  	seqv, isNil := indirect(seqv)
   352  	if isNil {
   353  		return nil, errors.New("can't iterate over a nil value")
   354  	}
   355  
   356  	switch seqv.Kind() {
   357  	case reflect.Array, reflect.Slice, reflect.String:
   358  		// okay
   359  	default:
   360  		return nil, errors.New("can't iterate over " + reflect.ValueOf(seq).Type().String())
   361  	}
   362  
   363  	if limitv > seqv.Len() {
   364  		limitv = seqv.Len()
   365  	}
   366  
   367  	return seqv.Slice(seqv.Len()-limitv, seqv.Len()).Interface(), nil
   368  }
   369  
   370  // Querify encodes the given parameters in URL-encoded form ("bar=baz&foo=quux") sorted by key.
   371  func (ns *Namespace) Querify(params ...interface{}) (string, error) {
   372  	qs := url.Values{}
   373  	vals, err := ns.Dictionary(params...)
   374  	if err != nil {
   375  		return "", errors.New("querify keys must be strings")
   376  	}
   377  
   378  	for name, value := range vals {
   379  		qs.Add(name, fmt.Sprintf("%v", value))
   380  	}
   381  
   382  	return qs.Encode(), nil
   383  }
   384  
   385  // Seq creates a sequence of integers.  It's named and used as GNU's seq.
   386  //
   387  // Examples:
   388  //     3 => 1, 2, 3
   389  //     1 2 4 => 1, 3
   390  //     -3 => -1, -2, -3
   391  //     1 4 => 1, 2, 3, 4
   392  //     1 -2 => 1, 0, -1, -2
   393  func (ns *Namespace) Seq(args ...interface{}) ([]int, error) {
   394  	if len(args) < 1 || len(args) > 3 {
   395  		return nil, errors.New("invalid number of arguments to Seq")
   396  	}
   397  
   398  	intArgs := cast.ToIntSlice(args)
   399  	if len(intArgs) < 1 || len(intArgs) > 3 {
   400  		return nil, errors.New("invalid arguments to Seq")
   401  	}
   402  
   403  	var inc = 1
   404  	var last int
   405  	var first = intArgs[0]
   406  
   407  	if len(intArgs) == 1 {
   408  		last = first
   409  		if last == 0 {
   410  			return []int{}, nil
   411  		} else if last > 0 {
   412  			first = 1
   413  		} else {
   414  			first = -1
   415  			inc = -1
   416  		}
   417  	} else if len(intArgs) == 2 {
   418  		last = intArgs[1]
   419  		if last < first {
   420  			inc = -1
   421  		}
   422  	} else {
   423  		inc = intArgs[1]
   424  		last = intArgs[2]
   425  		if inc == 0 {
   426  			return nil, errors.New("'increment' must not be 0")
   427  		}
   428  		if first < last && inc < 0 {
   429  			return nil, errors.New("'increment' must be > 0")
   430  		}
   431  		if first > last && inc > 0 {
   432  			return nil, errors.New("'increment' must be < 0")
   433  		}
   434  	}
   435  
   436  	// sanity check
   437  	if last < -100000 {
   438  		return nil, errors.New("size of result exceeds limit")
   439  	}
   440  	size := ((last - first) / inc) + 1
   441  
   442  	// sanity check
   443  	if size <= 0 || size > 2000 {
   444  		return nil, errors.New("size of result exceeds limit")
   445  	}
   446  
   447  	seq := make([]int, size)
   448  	val := first
   449  	for i := 0; ; i++ {
   450  		seq[i] = val
   451  		val += inc
   452  		if (inc < 0 && val < last) || (inc > 0 && val > last) {
   453  			break
   454  		}
   455  	}
   456  
   457  	return seq, nil
   458  }
   459  
   460  // Shuffle returns the given rangeable list in a randomised order.
   461  func (ns *Namespace) Shuffle(seq interface{}) (interface{}, error) {
   462  	if seq == nil {
   463  		return nil, errors.New("both count and seq must be provided")
   464  	}
   465  
   466  	seqv := reflect.ValueOf(seq)
   467  	seqv, isNil := indirect(seqv)
   468  	if isNil {
   469  		return nil, errors.New("can't iterate over a nil value")
   470  	}
   471  
   472  	switch seqv.Kind() {
   473  	case reflect.Array, reflect.Slice, reflect.String:
   474  		// okay
   475  	default:
   476  		return nil, errors.New("can't iterate over " + reflect.ValueOf(seq).Type().String())
   477  	}
   478  
   479  	shuffled := reflect.MakeSlice(reflect.TypeOf(seq), seqv.Len(), seqv.Len())
   480  
   481  	randomIndices := rand.Perm(seqv.Len())
   482  
   483  	for index, value := range randomIndices {
   484  		shuffled.Index(value).Set(seqv.Index(index))
   485  	}
   486  
   487  	return shuffled.Interface(), nil
   488  }
   489  
   490  // Slice returns a slice of all passed arguments.
   491  func (ns *Namespace) Slice(args ...interface{}) []interface{} {
   492  	return args
   493  }
   494  
   495  type intersector struct {
   496  	r    reflect.Value
   497  	seen map[interface{}]bool
   498  }
   499  
   500  func (i *intersector) appendIfNotSeen(v reflect.Value) {
   501  
   502  	vi := v.Interface()
   503  	if !i.seen[vi] {
   504  		i.r = reflect.Append(i.r, v)
   505  		i.seen[vi] = true
   506  	}
   507  }
   508  
   509  func (i *intersector) handleValuePair(l1vv, l2vv reflect.Value) {
   510  	switch kind := l1vv.Kind(); {
   511  	case kind == reflect.String:
   512  		l2t, err := toString(l2vv)
   513  		if err == nil && l1vv.String() == l2t {
   514  			i.appendIfNotSeen(l1vv)
   515  		}
   516  	case isNumber(kind):
   517  		f1, err1 := numberToFloat(l1vv)
   518  		f2, err2 := numberToFloat(l2vv)
   519  		if err1 == nil && err2 == nil && f1 == f2 {
   520  			i.appendIfNotSeen(l1vv)
   521  		}
   522  	case kind == reflect.Ptr, kind == reflect.Struct:
   523  		if l1vv.Interface() == l2vv.Interface() {
   524  			i.appendIfNotSeen(l1vv)
   525  		}
   526  	case kind == reflect.Interface:
   527  		i.handleValuePair(reflect.ValueOf(l1vv.Interface()), l2vv)
   528  	}
   529  }
   530  
   531  // Union returns the union of the given sets, l1 and l2. l1 and
   532  // l2 must be of the same type and may be either arrays or slices.
   533  // If l1 and l2 aren't of the same type then l1 will be returned.
   534  // If either l1 or l2 is nil then the non-nil list will be returned.
   535  func (ns *Namespace) Union(l1, l2 interface{}) (interface{}, error) {
   536  	if l1 == nil && l2 == nil {
   537  		return []interface{}{}, nil
   538  	} else if l1 == nil && l2 != nil {
   539  		return l2, nil
   540  	} else if l1 != nil && l2 == nil {
   541  		return l1, nil
   542  	}
   543  
   544  	l1v := reflect.ValueOf(l1)
   545  	l2v := reflect.ValueOf(l2)
   546  
   547  	var ins *intersector
   548  
   549  	switch l1v.Kind() {
   550  	case reflect.Array, reflect.Slice:
   551  		switch l2v.Kind() {
   552  		case reflect.Array, reflect.Slice:
   553  			ins = &intersector{r: reflect.MakeSlice(l1v.Type(), 0, 0), seen: make(map[interface{}]bool)}
   554  
   555  			if l1v.Type() != l2v.Type() &&
   556  				l1v.Type().Elem().Kind() != reflect.Interface &&
   557  				l2v.Type().Elem().Kind() != reflect.Interface {
   558  				return ins.r.Interface(), nil
   559  			}
   560  
   561  			var (
   562  				l1vv  reflect.Value
   563  				isNil bool
   564  			)
   565  
   566  			for i := 0; i < l1v.Len(); i++ {
   567  				l1vv, isNil = indirectInterface(l1v.Index(i))
   568  				if !isNil {
   569  					ins.appendIfNotSeen(l1vv)
   570  				}
   571  			}
   572  
   573  			if !l1vv.IsValid() {
   574  				// The first slice may be empty. Pick the first value of the second
   575  				// to use as a prototype.
   576  				if l2v.Len() > 0 {
   577  					l1vv = l2v.Index(0)
   578  				}
   579  			}
   580  
   581  			for j := 0; j < l2v.Len(); j++ {
   582  				l2vv := l2v.Index(j)
   583  
   584  				switch kind := l1vv.Kind(); {
   585  				case kind == reflect.String:
   586  					l2t, err := toString(l2vv)
   587  					if err == nil {
   588  						ins.appendIfNotSeen(reflect.ValueOf(l2t))
   589  					}
   590  				case isNumber(kind):
   591  					var err error
   592  					l2vv, err = convertNumber(l2vv, kind)
   593  					if err == nil {
   594  						ins.appendIfNotSeen(l2vv)
   595  					}
   596  				case kind == reflect.Interface, kind == reflect.Struct, kind == reflect.Ptr:
   597  					ins.appendIfNotSeen(l2vv)
   598  
   599  				}
   600  			}
   601  
   602  			return ins.r.Interface(), nil
   603  		default:
   604  			return nil, errors.New("can't iterate over " + reflect.ValueOf(l2).Type().String())
   605  		}
   606  	default:
   607  		return nil, errors.New("can't iterate over " + reflect.ValueOf(l1).Type().String())
   608  	}
   609  }
   610  
   611  // Uniq takes in a slice or array and returns a slice with subsequent
   612  // duplicate elements removed.
   613  func (ns *Namespace) Uniq(l interface{}) (interface{}, error) {
   614  	if l == nil {
   615  		return make([]interface{}, 0), nil
   616  	}
   617  
   618  	lv := reflect.ValueOf(l)
   619  	lv, isNil := indirect(lv)
   620  	if isNil {
   621  		return nil, errors.New("invalid nil argument to Uniq")
   622  	}
   623  
   624  	var ret reflect.Value
   625  
   626  	switch lv.Kind() {
   627  	case reflect.Slice:
   628  		ret = reflect.MakeSlice(lv.Type(), 0, 0)
   629  	case reflect.Array:
   630  		ret = reflect.MakeSlice(reflect.SliceOf(lv.Type().Elem()), 0, 0)
   631  	default:
   632  		return nil, errors.New("Can't use Uniq on " + reflect.ValueOf(lv).Type().String())
   633  	}
   634  
   635  	for i := 0; i != lv.Len(); i++ {
   636  		lvv := lv.Index(i)
   637  		lvv, isNil := indirect(lvv)
   638  		if isNil {
   639  			continue
   640  		}
   641  
   642  		if !ns.In(ret.Interface(), lvv.Interface()) {
   643  			ret = reflect.Append(ret, lvv)
   644  		}
   645  	}
   646  	return ret.Interface(), nil
   647  }
   648  
   649  // KeyVals creates a key and values wrapper.
   650  func (ns *Namespace) KeyVals(key interface{}, vals ...interface{}) (types.KeyValues, error) {
   651  	return types.KeyValues{Key: key, Values: vals}, nil
   652  }