github.com/hairyhenderson/templater@v3.5.0+incompatible/funcs/random.go (about) 1 package funcs 2 3 import ( 4 "reflect" 5 "strconv" 6 "sync" 7 "unicode/utf8" 8 9 "github.com/hairyhenderson/gomplate/conv" 10 "github.com/hairyhenderson/gomplate/random" 11 "github.com/pkg/errors" 12 ) 13 14 var ( 15 randomNS *RandomFuncs 16 randomNSInit sync.Once 17 ) 18 19 // RandomNS - 20 func RandomNS() *RandomFuncs { 21 randomNSInit.Do(func() { randomNS = &RandomFuncs{} }) 22 return randomNS 23 } 24 25 // AddRandomFuncs - 26 func AddRandomFuncs(f map[string]interface{}) { 27 f["random"] = RandomNS 28 } 29 30 // RandomFuncs - 31 type RandomFuncs struct{} 32 33 // ASCII - 34 func (f *RandomFuncs) ASCII(count interface{}) (string, error) { 35 return random.StringBounds(conv.ToInt(count), ' ', '~') 36 } 37 38 // Alpha - 39 func (f *RandomFuncs) Alpha(count interface{}) (string, error) { 40 return random.StringRE(conv.ToInt(count), "[[:alpha:]]") 41 } 42 43 // AlphaNum - 44 func (f *RandomFuncs) AlphaNum(count interface{}) (string, error) { 45 return random.StringRE(conv.ToInt(count), "[[:alnum:]]") 46 } 47 48 // String - 49 func (f *RandomFuncs) String(count interface{}, args ...interface{}) (s string, err error) { 50 c := conv.ToInt(count) 51 if c == 0 { 52 return "", errors.New("count must be greater than 0") 53 } 54 m := "" 55 switch len(args) { 56 case 0: 57 m = "" 58 case 1: 59 m = conv.ToString(args[0]) 60 case 2: 61 var l, u rune 62 if isString(args[0]) && isString(args[1]) { 63 l, u, err = toCodePoints(args[0].(string), args[1].(string)) 64 if err != nil { 65 return "", err 66 } 67 } else { 68 l = rune(conv.ToInt(args[0])) 69 u = rune(conv.ToInt(args[1])) 70 } 71 72 return random.StringBounds(c, l, u) 73 } 74 75 return random.StringRE(c, m) 76 } 77 78 func isString(s interface{}) bool { 79 switch s.(type) { 80 case string: 81 return true 82 default: 83 return false 84 } 85 } 86 87 var rlen = utf8.RuneCountInString 88 89 func toCodePoints(l, u string) (rune, rune, error) { 90 // no way are these representing valid printable codepoints - we'll treat 91 // them as runes 92 if rlen(l) == rlen(u) && rlen(l) == 1 { 93 lower, _ := utf8.DecodeRuneInString(l) 94 upper, _ := utf8.DecodeRuneInString(u) 95 return lower, upper, nil 96 } 97 98 li, err := strconv.ParseInt(l, 0, 32) 99 if err != nil { 100 return 0, 0, err 101 } 102 ui, err := strconv.ParseInt(u, 0, 32) 103 if err != nil { 104 return 0, 0, err 105 } 106 107 return rune(li), rune(ui), nil 108 } 109 110 func interfaceSlice(slice interface{}) ([]interface{}, error) { 111 s := reflect.ValueOf(slice) 112 kind := s.Kind() 113 switch kind { 114 case reflect.Slice, reflect.Array: 115 ret := make([]interface{}, s.Len()) 116 for i := 0; i < s.Len(); i++ { 117 ret[i] = s.Index(i).Interface() 118 } 119 return ret, nil 120 default: 121 return nil, errors.Errorf("expected an array or slice, but got a %T", s) 122 } 123 } 124 125 // Item - 126 func (f *RandomFuncs) Item(items interface{}) (interface{}, error) { 127 i, err := interfaceSlice(items) 128 if err != nil { 129 return nil, err 130 } 131 return random.Item(i) 132 } 133 134 // Number - 135 func (f *RandomFuncs) Number(args ...interface{}) (int64, error) { 136 var min, max int64 137 min, max = 0, 100 138 switch len(args) { 139 case 0: 140 case 1: 141 max = conv.ToInt64(args[0]) 142 case 2: 143 min = conv.ToInt64(args[0]) 144 max = conv.ToInt64(args[1]) 145 } 146 return random.Number(min, max) 147 } 148 149 // Float - 150 func (f *RandomFuncs) Float(args ...interface{}) (float64, error) { 151 var min, max float64 152 min, max = 0, 1.0 153 switch len(args) { 154 case 0: 155 case 1: 156 max = conv.ToFloat64(args[0]) 157 case 2: 158 min = conv.ToFloat64(args[0]) 159 max = conv.ToFloat64(args[1]) 160 } 161 return random.Float(min, max) 162 }