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  }