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 }