github.com/wuhuizuo/gomplate@v3.5.0+incompatible/funcs/strings.go (about)

     1  package funcs
     2  
     3  // Namespace strings contains mostly wrappers of equivalently-named
     4  // functions in the standard library `strings` package, with
     5  // differences in argument order where it makes pipelining
     6  // in templates easier.
     7  
     8  import (
     9  	"fmt"
    10  	"sync"
    11  	"unicode/utf8"
    12  
    13  	"github.com/Masterminds/goutils"
    14  	"github.com/hairyhenderson/gomplate/conv"
    15  	"github.com/pkg/errors"
    16  
    17  	"strings"
    18  
    19  	"github.com/gosimple/slug"
    20  	gompstrings "github.com/hairyhenderson/gomplate/strings"
    21  )
    22  
    23  var (
    24  	strNS     *StringFuncs
    25  	strNSInit sync.Once
    26  )
    27  
    28  // StrNS -
    29  func StrNS() *StringFuncs {
    30  	strNSInit.Do(func() { strNS = &StringFuncs{} })
    31  	return strNS
    32  }
    33  
    34  // AddStringFuncs -
    35  func AddStringFuncs(f map[string]interface{}) {
    36  	f["strings"] = StrNS
    37  
    38  	f["replaceAll"] = StrNS().ReplaceAll
    39  	f["title"] = StrNS().Title
    40  	f["toUpper"] = StrNS().ToUpper
    41  	f["toLower"] = StrNS().ToLower
    42  	f["trimSpace"] = StrNS().TrimSpace
    43  	f["indent"] = StrNS().Indent
    44  	f["quote"] = StrNS().Quote
    45  	f["squote"] = StrNS().Squote
    46  
    47  	// these are legacy aliases with non-pipelinable arg order
    48  	f["contains"] = strings.Contains
    49  	f["hasPrefix"] = strings.HasPrefix
    50  	f["hasSuffix"] = strings.HasSuffix
    51  	f["split"] = strings.Split
    52  	f["splitN"] = strings.SplitN
    53  	f["trim"] = strings.Trim
    54  }
    55  
    56  // StringFuncs -
    57  type StringFuncs struct{}
    58  
    59  // Abbrev -
    60  func (f *StringFuncs) Abbrev(args ...interface{}) (string, error) {
    61  	str := ""
    62  	offset := 0
    63  	maxWidth := 0
    64  	if len(args) < 2 {
    65  		return "", errors.Errorf("abbrev requires a 'maxWidth' and 'input' argument")
    66  	}
    67  	if len(args) == 2 {
    68  		maxWidth = conv.ToInt(args[0])
    69  		str = conv.ToString(args[1])
    70  	}
    71  	if len(args) == 3 {
    72  		offset = conv.ToInt(args[0])
    73  		maxWidth = conv.ToInt(args[1])
    74  		str = conv.ToString(args[2])
    75  	}
    76  	if len(str) <= maxWidth {
    77  		return str, nil
    78  	}
    79  	return goutils.AbbreviateFull(str, offset, maxWidth)
    80  }
    81  
    82  // ReplaceAll -
    83  func (f *StringFuncs) ReplaceAll(old, new string, s interface{}) string {
    84  	return strings.Replace(conv.ToString(s), old, new, -1)
    85  }
    86  
    87  // Contains -
    88  func (f *StringFuncs) Contains(substr string, s interface{}) bool {
    89  	return strings.Contains(conv.ToString(s), substr)
    90  }
    91  
    92  // HasPrefix -
    93  func (f *StringFuncs) HasPrefix(prefix string, s interface{}) bool {
    94  	return strings.HasPrefix(conv.ToString(s), prefix)
    95  }
    96  
    97  // HasSuffix -
    98  func (f *StringFuncs) HasSuffix(suffix string, s interface{}) bool {
    99  	return strings.HasSuffix(conv.ToString(s), suffix)
   100  }
   101  
   102  // Repeat -
   103  func (f *StringFuncs) Repeat(count int, s interface{}) (string, error) {
   104  	if count < 0 {
   105  		return "", errors.Errorf("negative count %d", count)
   106  	}
   107  	str := conv.ToString(s)
   108  	if count > 0 && len(str)*count/count != len(str) {
   109  		return "", errors.Errorf("count %d too long: causes overflow", count)
   110  	}
   111  	return strings.Repeat(str, count), nil
   112  }
   113  
   114  // Sort -
   115  //
   116  // Deprecated: use coll.Sort instead
   117  func (f *StringFuncs) Sort(list interface{}) ([]string, error) {
   118  	switch v := list.(type) {
   119  	case []string:
   120  		return gompstrings.Sort(v), nil
   121  	case []interface{}:
   122  		l := len(v)
   123  		b := make([]string, len(v))
   124  		for i := 0; i < l; i++ {
   125  			b[i] = conv.ToString(v[i])
   126  		}
   127  		return gompstrings.Sort(b), nil
   128  	default:
   129  		return nil, errors.Errorf("wrong type for value; expected []string; got %T", list)
   130  	}
   131  }
   132  
   133  // Split -
   134  func (f *StringFuncs) Split(sep string, s interface{}) []string {
   135  	return strings.Split(conv.ToString(s), sep)
   136  }
   137  
   138  // SplitN -
   139  func (f *StringFuncs) SplitN(sep string, n int, s interface{}) []string {
   140  	return strings.SplitN(conv.ToString(s), sep, n)
   141  }
   142  
   143  // Trim -
   144  func (f *StringFuncs) Trim(cutset string, s interface{}) string {
   145  	return strings.Trim(conv.ToString(s), cutset)
   146  }
   147  
   148  // TrimPrefix -
   149  func (f *StringFuncs) TrimPrefix(cutset string, s interface{}) string {
   150  	return strings.TrimPrefix(conv.ToString(s), cutset)
   151  }
   152  
   153  // TrimSuffix -
   154  func (f *StringFuncs) TrimSuffix(cutset string, s interface{}) string {
   155  	return strings.TrimSuffix(conv.ToString(s), cutset)
   156  }
   157  
   158  // Title -
   159  func (f *StringFuncs) Title(s interface{}) string {
   160  	return strings.Title(conv.ToString(s))
   161  }
   162  
   163  // ToUpper -
   164  func (f *StringFuncs) ToUpper(s interface{}) string {
   165  	return strings.ToUpper(conv.ToString(s))
   166  }
   167  
   168  // ToLower -
   169  func (f *StringFuncs) ToLower(s interface{}) string {
   170  	return strings.ToLower(conv.ToString(s))
   171  }
   172  
   173  // TrimSpace -
   174  func (f *StringFuncs) TrimSpace(s interface{}) string {
   175  	return strings.TrimSpace(conv.ToString(s))
   176  }
   177  
   178  // Trunc -
   179  func (f *StringFuncs) Trunc(length int, s interface{}) string {
   180  	return gompstrings.Trunc(length, conv.ToString(s))
   181  }
   182  
   183  // Indent -
   184  func (f *StringFuncs) Indent(args ...interface{}) (string, error) {
   185  	input := conv.ToString(args[len(args)-1])
   186  	indent := " "
   187  	width := 1
   188  	var ok bool
   189  	switch len(args) {
   190  	case 2:
   191  		indent, ok = args[0].(string)
   192  		if !ok {
   193  			width, ok = args[0].(int)
   194  			if !ok {
   195  				return "", errors.New("Indent: invalid arguments")
   196  			}
   197  			indent = " "
   198  		}
   199  	case 3:
   200  		width, ok = args[0].(int)
   201  		if !ok {
   202  			return "", errors.New("Indent: invalid arguments")
   203  		}
   204  		indent, ok = args[1].(string)
   205  		if !ok {
   206  			return "", errors.New("Indent: invalid arguments")
   207  		}
   208  	}
   209  	return gompstrings.Indent(width, indent, input), nil
   210  }
   211  
   212  // Slug -
   213  func (f *StringFuncs) Slug(in interface{}) string {
   214  	return slug.Make(conv.ToString(in))
   215  }
   216  
   217  // Quote -
   218  func (f *StringFuncs) Quote(in interface{}) string {
   219  	return fmt.Sprintf("%q", conv.ToString(in))
   220  }
   221  
   222  // Squote -
   223  func (f *StringFuncs) Squote(in interface{}) string {
   224  	s := conv.ToString(in)
   225  	s = strings.Replace(s, `'`, `''`, -1)
   226  	return fmt.Sprintf("'%s'", s)
   227  }
   228  
   229  // SnakeCase -
   230  func (f *StringFuncs) SnakeCase(in interface{}) (string, error) {
   231  	return gompstrings.SnakeCase(conv.ToString(in)), nil
   232  }
   233  
   234  // CamelCase -
   235  func (f *StringFuncs) CamelCase(in interface{}) (string, error) {
   236  	return gompstrings.CamelCase(conv.ToString(in)), nil
   237  }
   238  
   239  // KebabCase -
   240  func (f *StringFuncs) KebabCase(in interface{}) (string, error) {
   241  	return gompstrings.KebabCase(conv.ToString(in)), nil
   242  }
   243  
   244  // WordWrap -
   245  func (f *StringFuncs) WordWrap(args ...interface{}) (string, error) {
   246  	if len(args) == 0 || len(args) > 3 {
   247  		return "", errors.Errorf("expected 1, 2, or 3 args, got %d", len(args))
   248  	}
   249  	in := conv.ToString(args[len(args)-1])
   250  
   251  	opts := gompstrings.WordWrapOpts{}
   252  	if len(args) == 2 {
   253  		switch a := (args[0]).(type) {
   254  		case string:
   255  			opts.LBSeq = a
   256  		default:
   257  			opts.Width = uint(conv.ToInt(a))
   258  		}
   259  	}
   260  	if len(args) == 3 {
   261  		opts.Width = uint(conv.ToInt(args[0]))
   262  		opts.LBSeq = conv.ToString(args[1])
   263  	}
   264  	return gompstrings.WordWrap(in, opts), nil
   265  }
   266  
   267  // RuneCount - like len(s), but for runes
   268  func (f *StringFuncs) RuneCount(args ...interface{}) (int, error) {
   269  	s := ""
   270  	for _, arg := range args {
   271  		s += conv.ToString(arg)
   272  	}
   273  	return utf8.RuneCountInString(s), nil
   274  }