diff options
Diffstat (limited to 'tpl/collections/append.go')
-rw-r--r-- | tpl/collections/append.go | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/tpl/collections/append.go b/tpl/collections/append.go new file mode 100644 index 000000000..20afa0e72 --- /dev/null +++ b/tpl/collections/append.go @@ -0,0 +1,74 @@ +// Copyright 2018 The Hugo Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package collections + +import ( + "errors" + "fmt" + "reflect" +) + +// Append appends the arguments up to the last one to the slice in the last argument. +// This construct allows template constructs like this: +// {{ $pages = $pages | append $p2 $p1 }} +// Note that with 2 arguments where both are slices of the same type, +// the first slice will be appended to the second: +// {{ $pages = $pages | append .Site.RegularPages }} +func (ns *Namespace) Append(args ...interface{}) (interface{}, error) { + if len(args) < 2 { + return nil, errors.New("need at least 2 arguments to append") + } + + to := args[len(args)-1] + from := args[:len(args)-1] + + tov, toIsNil := indirect(reflect.ValueOf(to)) + + toIsNil = toIsNil || to == nil + var tot reflect.Type + + if !toIsNil { + if tov.Kind() != reflect.Slice { + return nil, fmt.Errorf("expected a slice, got %T", to) + } + + tot = tov.Type().Elem() + toIsNil = tov.Len() == 0 + + if len(from) == 1 { + // If we get []string []string, we append the from slice to to + fromv := reflect.ValueOf(from[0]) + if fromv.Kind() == reflect.Slice { + fromt := reflect.TypeOf(from[0]).Elem() + if tot == fromt { + return reflect.AppendSlice(tov, fromv).Interface(), nil + } + } + } + } + + if toIsNil { + return ns.Slice(from...), nil + } + + for _, f := range from { + fv := reflect.ValueOf(f) + if tot != fv.Type() { + return nil, fmt.Errorf("append element type mismatch: expected %v, got %v", tot, fv.Type()) + } + tov = reflect.Append(tov, fv) + } + + return tov.Interface(), nil +} |