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 }