// substr extracts parts of a string, beginning at the character at the specified // position, and returns the specified number of characters. // // It normally takes two parameters: start and length. // It can also take one parameter: start, i.e. length is omitted, in which case // the substring starting from start until the end of the string will be returned. // // To extract characters from the end of the string, use a negative start number. // // In addition, borrowing from the extended behavior described at http://php.net/substr, // if length is given and is negative, then that many characters will be omitted from // the end of string. func substr(a interface{}, nums ...interface{}) (string, error) { aStr, err := cast.ToStringE(a) if err != nil { return "", err } var start, length int asRunes := []rune(aStr) switch len(nums) { case 0: return "", errors.New("too less arguments") case 1: if start, err = cast.ToIntE(nums[0]); err != nil { return "", errors.New("start argument must be integer") } length = len(asRunes) case 2: if start, err = cast.ToIntE(nums[0]); err != nil { return "", errors.New("start argument must be integer") } if length, err = cast.ToIntE(nums[1]); err != nil { return "", errors.New("length argument must be integer") } default: return "", errors.New("too many arguments") } if start < -len(asRunes) { start = 0 } if start > len(asRunes) { return "", fmt.Errorf("start position out of bounds for %d-byte string", len(aStr)) } var s, e int if start >= 0 && length >= 0 { s = start e = start + length } else if start < 0 && length >= 0 { s = len(asRunes) + start - length + 1 e = len(asRunes) + start + 1 } else if start >= 0 && length < 0 { s = start e = len(asRunes) + length } else { s = len(asRunes) + start e = len(asRunes) + length } if s > e { return "", fmt.Errorf("calculated start position greater than end position: %d > %d", s, e) } if e > len(asRunes) { e = len(asRunes) } return string(asRunes[s:e]), nil }
// After is exposed to templates, to iterate over all the items after N in a // rangeable list. It's meant to accompany First func After(index interface{}, seq interface{}) (interface{}, error) { if index == nil || seq == nil { return nil, errors.New("both limit and seq must be provided") } indexv, err := cast.ToIntE(index) if err != nil { return nil, err } if indexv < 1 { return nil, errors.New("can't return negative/empty count of items from sequence") } seqv := reflect.ValueOf(seq) seqv, isNil := indirect(seqv) if isNil { return nil, errors.New("can't iterate over a nil value") } switch seqv.Kind() { case reflect.Array, reflect.Slice, reflect.String: // okay default: return nil, errors.New("can't iterate over " + reflect.ValueOf(seq).Type().String()) } if indexv >= seqv.Len() { return nil, errors.New("no items left") } return seqv.Slice(indexv, seqv.Len()).Interface(), nil }
func (self *Options) Int(key string) int { value, err := cast.ToIntE(self.Interface(key)) if err != nil { self.log.Printf("%s for key '%s'", err.Error(), key) } return value }
// First is exposed to templates, to iterate over the first N items in a // rangeable list. func First(limit interface{}, seq interface{}) (interface{}, error) { limitv, err := cast.ToIntE(limit) if err != nil { return nil, err } if limitv < 1 { return nil, errors.New("can't return negative/empty count of items from sequence") } seqv := reflect.ValueOf(seq) seqv, isNil := indirect(seqv) if isNil { return nil, errors.New("can't iterate over a nil value") } switch seqv.Kind() { case reflect.Array, reflect.Slice, reflect.String: // okay default: return nil, errors.New("can't iterate over " + reflect.ValueOf(seq).Type().String()) } if limitv > seqv.Len() { limitv = seqv.Len() } return seqv.Slice(0, limitv).Interface(), nil }
func (c *Configr) Int(key string) (int, error) { val, err := c.Get(key) if err != nil { return 0, err } return cast.ToIntE(val) }
// First is exposed to templates, to iterate over the first N items in a // rangeable list. func First(limit interface{}, seq interface{}) (interface{}, error) { limitv, err := cast.ToIntE(limit) if err != nil { return nil, err } if limitv < 1 { return nil, errors.New("can't return negative/empty count of items from sequence") } seqv := reflect.ValueOf(seq) // this is better than my first pass; ripped from text/template/exec.go indirect(): for ; seqv.Kind() == reflect.Ptr || seqv.Kind() == reflect.Interface; seqv = seqv.Elem() { if seqv.IsNil() { return nil, errors.New("can't iterate over a nil value") } if seqv.Kind() == reflect.Interface && seqv.NumMethod() > 0 { break } } switch seqv.Kind() { case reflect.Array, reflect.Slice, reflect.String: // okay default: return nil, errors.New("can't iterate over " + reflect.ValueOf(seq).Type().String()) } if limitv > seqv.Len() { limitv = seqv.Len() } return seqv.Slice(0, limitv).Interface(), nil }
// slicestr slices a string by specifying a half-open range with // two indices, start and end. 1 and 4 creates a slice including elements 1 through 3. // The end index can be omitted, it defaults to the string's length. func slicestr(a interface{}, startEnd ...interface{}) (string, error) { aStr, err := cast.ToStringE(a) if err != nil { return "", err } var argStart, argEnd int argNum := len(startEnd) if argNum > 0 { if argStart, err = cast.ToIntE(startEnd[0]); err != nil { return "", errors.New("start argument must be integer") } } if argNum > 1 { if argEnd, err = cast.ToIntE(startEnd[1]); err != nil { return "", errors.New("end argument must be integer") } } if argNum > 2 { return "", errors.New("too many arguments") } asRunes := []rune(aStr) if argNum > 0 && (argStart < 0 || argStart >= len(asRunes)) { return "", errors.New("slice bounds out of range") } if argNum == 2 { if argEnd < 0 || argEnd > len(asRunes) { return "", errors.New("slice bounds out of range") } return string(asRunes[argStart:argEnd]), nil } else if argNum == 1 { return string(asRunes[argStart:]), nil } else { return string(asRunes[:]), nil } }
// GetInt takes the name of an argument and returns an integer and an error func (args Args) GetInt(name string) (int, error) { v, ok := args[name] if !ok { return -1 << 7, ErrNoArg } i, err := cast.ToIntE(v) if err != nil { return -1 << 7, err } return i, nil }
func resolvePagerSize(options ...interface{}) (int, error) { if len(options) == 0 { return viper.GetInt("paginate"), nil } if len(options) > 1 { return -1, errors.New("too many arguments, 'pager size' is currently the only option") } pas, err := cast.ToIntE(options[0]) if err != nil || pas <= 0 { return -1, errors.New(("'pager size' must be a positive integer")) } return pas, nil }