func Delimit(seq, delimiter interface{}, last ...interface{}) (template.HTML, error) { d, err := cast.ToStringE(delimiter) if err != nil { return "", err } var dLast *string for _, l := range last { dStr, err := cast.ToStringE(l) if err != nil { dLast = nil } dLast = &dStr break } seqv := reflect.ValueOf(seq) seqv, isNil := indirect(seqv) if isNil { return "", errors.New("can't iterate over a nil value") } var str string switch seqv.Kind() { case reflect.Map: sortSeq, err := Sort(seq) if err != nil { return "", err } seqv = reflect.ValueOf(sortSeq) fallthrough case reflect.Array, reflect.Slice, reflect.String: for i := 0; i < seqv.Len(); i++ { val := seqv.Index(i).Interface() valStr, err := cast.ToStringE(val) if err != nil { continue } switch { case i == seqv.Len()-2 && dLast != nil: str += valStr + *dLast case i == seqv.Len()-1: str += valStr default: str += valStr + d } } default: return "", errors.New("can't iterate over " + reflect.ValueOf(seq).Type().String()) } return template.HTML(str), nil }
// Replace all occurences of b with c in a func Replace(a, b, c interface{}) (string, error) { aStr, err := cast.ToStringE(a) if err != nil { return "", err } bStr, err := cast.ToStringE(b) if err != nil { return "", err } cStr, err := cast.ToStringE(c) if err != nil { return "", err } return strings.Replace(aStr, bStr, cStr, -1), nil }
func (self *Options) String(key string) string { value, err := cast.ToStringE(self.Interface(key)) if err != nil { self.log.Printf("%s for key '%s'", err.Error(), key) } return value }
// singularize returns the singular form of a single word. func singularize(in interface{}) (string, error) { word, err := cast.ToStringE(in) if err != nil { return "", err } return inflect.Singularize(word), nil }
// 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 }
// Param is a convenience method to do lookups in Site's Params map. // // This method is also implemented on Page. func (n *Node) Param(key interface{}) (interface{}, error) { keyStr, err := cast.ToStringE(key) if err != nil { return nil, err } return n.Site.Params[keyStr], err }
// Trim leading/trailing characters defined by b from a func Trim(a interface{}, b string) (string, error) { aStr, err := cast.ToStringE(a) if err != nil { return "", err } return strings.Trim(aStr, b), nil }
func htmlUnescape(in interface{}) (string, error) { conv, err := cast.ToStringE(in) if err != nil { return "", err } return html.UnescapeString(conv), nil }
// Slicing in Slicestr is done 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 ...int) (string, error) { aStr, err := cast.ToStringE(a) if err != nil { return "", err } if len(startEnd) > 2 { return "", errors.New("too many arguments") } asRunes := []rune(aStr) if len(startEnd) > 0 && (startEnd[0] < 0 || startEnd[0] >= len(asRunes)) { return "", errors.New("slice bounds out of range") } if len(startEnd) == 2 { if startEnd[1] < 0 || startEnd[1] > len(asRunes) { return "", errors.New("slice bounds out of range") } return string(asRunes[startEnd[0]:startEnd[1]]), nil } else if len(startEnd) == 1 { return string(asRunes[startEnd[0]:]), nil } else { return string(asRunes[:]), nil } }
func Split(a interface{}, delimiter string) ([]string, error) { aStr, err := cast.ToStringE(a) if err != nil { return []string{}, err } return strings.Split(aStr, delimiter), nil }
func (c *Configr) String(key string) (string, error) { val, err := c.Get(key) if err != nil { return "", err } return cast.ToStringE(val) }
// emojify "emojifies" the given string. // // See http://www.emoji-cheat-sheet.com/ func emojify(in interface{}) (template.HTML, error) { str, err := cast.ToStringE(in) if err != nil { return "", err } return template.HTML(helpers.Emojify([]byte(str))), nil }
func Chomp(text interface{}) (string, error) { s, err := cast.ToStringE(text) if err != nil { return "", err } return strings.TrimRight(s, "\r\n"), nil }
// chomp removes trailing newline characters from a string. func chomp(text interface{}) (template.HTML, error) { s, err := cast.ToStringE(text) if err != nil { return "", err } return template.HTML(strings.TrimRight(s, "\r\n")), nil }
// sha1 hashes the given input and returns its SHA1 checksum func sha1(in interface{}) (string, error) { conv, err := cast.ToStringE(in) if err != nil { return "", err } hash := _sha1.Sum([]byte(conv)) return hex.EncodeToString(hash[:]), nil }
// highlight returns an HTML string with syntax highlighting applied. func highlight(in interface{}, lang, opts string) (template.HTML, error) { str, err := cast.ToStringE(in) if err != nil { return "", err } return template.HTML(helpers.Highlight(html.UnescapeString(str), lang, opts)), nil }
// plainify strips any HTML and returns the plain text version. func plainify(in interface{}) (string, error) { s, err := cast.ToStringE(in) if err != nil { return "", err } return helpers.StripHTML(s), nil }
// base64Encode returns the base64 encoding of the given content. func base64Encode(content interface{}) (string, error) { conv, err := cast.ToStringE(content) if err != nil { return "", err } return base64.StdEncoding.EncodeToString([]byte(conv)), nil }
// Param is a convenience method to do lookups in Page's and Site's Params map, // in that order. // // This method is also implemented on Node. func (p *Page) Param(key interface{}) (interface{}, error) { keyStr, err := cast.ToStringE(key) if err != nil { return nil, err } if val, ok := p.Params[keyStr]; ok { return val, nil } return p.Site.Params[keyStr], nil }
func (p *Page) Menus() PageMenus { p.pageMenusInit.Do(func() { p.pageMenus = PageMenus{} if ms, ok := p.Params["menu"]; ok { link, _ := p.RelPermalink() me := MenuEntry{Name: p.LinkTitle(), Weight: p.Weight, URL: link} // Could be the name of the menu to attach it to mname, err := cast.ToStringE(ms) if err == nil { me.Menu = mname p.pageMenus[mname] = &me return } // Could be a slice of strings mnames, err := cast.ToStringSliceE(ms) if err == nil { for _, mname := range mnames { me.Menu = mname p.pageMenus[mname] = &me } return } // Could be a structured menu entry menus, err := cast.ToStringMapE(ms) if err != nil { jww.ERROR.Printf("unable to process menus for %q\n", p.Title) } for name, menu := range menus { menuEntry := MenuEntry{Name: p.LinkTitle(), URL: link, Weight: p.Weight, Menu: name} if menu != nil { jww.DEBUG.Printf("found menu: %q, in %q\n", name, p.Title) ime, err := cast.ToStringMapE(menu) if err != nil { jww.ERROR.Printf("unable to process menus for %q: %s", p.Title, err) } menuEntry.marshallMap(ime) } p.pageMenus[name] = &menuEntry } } }) return p.pageMenus }
// base64Decode returns the base64 decoding of the given content. func base64Decode(content interface{}) (string, error) { conv, err := cast.ToStringE(content) if err != nil { return "", err } dec, err := base64.StdEncoding.DecodeString(conv) return string(dec), err }
// GetString takes the name of an argument and returns a string and an error. func (args Args) GetString(name string) (string, error) { v, ok := args[name] if !ok { return "<invalid argument>", ErrNoArg } str, err := cast.ToStringE(v) if err != nil { return "<failed to cast>", err } return str, nil }
// humanize returns the humanized form of a single word. // Example: "my-first-post" -> "My first post" func humanize(in interface{}) (string, error) { word, err := cast.ToStringE(in) if err != nil { return "", err } if word == "" { return "", nil } return inflect.Humanize(word), nil }
func (page *Page) Menus() PageMenus { ret := PageMenus{} if ms, ok := page.Params["menu"]; ok { link, _ := page.Permalink() me := MenuEntry{Name: page.LinkTitle(), Weight: page.Weight, Url: link} // Could be the name of the menu to attach it to mname, err := cast.ToStringE(ms) if err == nil { me.Menu = mname ret[mname] = &me return ret } // Could be an slice of strings mnames, err := cast.ToStringSliceE(ms) if err == nil { for _, mname := range mnames { me.Menu = mname ret[mname] = &me return ret } } // Could be a structured menu entry menus, err := cast.ToStringMapE(ms) if err != nil { jww.ERROR.Printf("unable to process menus for %q\n", page.Title) } for name, menu := range menus { menuEntry := MenuEntry{Name: page.LinkTitle(), Url: link, Weight: page.Weight, Menu: name} jww.DEBUG.Printf("found menu: %q, in %q\n", name, page.Title) ime, err := cast.ToStringMapE(menu) if err != nil { jww.ERROR.Printf("unable to process menus for %q\n", page.Title) } menuEntry.MarshallMap(ime) ret[name] = &menuEntry } return ret } return nil }
// replaceRE exposes a regular expression replacement function to the templates. func replaceRE(pattern, repl, src interface{}) (_ string, err error) { patternStr, err := cast.ToStringE(pattern) if err != nil { return } replStr, err := cast.ToStringE(repl) if err != nil { return } srcStr, err := cast.ToStringE(src) if err != nil { return } re, err := reCache.Get(patternStr) if err != nil { return "", err } return re.ReplaceAllString(srcStr, replStr), nil }
// 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 ...int) (string, error) { aStr, err := cast.ToStringE(a) if err != nil { return "", err } var start, length int switch len(nums) { case 1: start = nums[0] length = len(aStr) case 2: start = nums[0] length = nums[1] default: return "", errors.New("too many arguments") } if start < -len(aStr) { start = 0 } if start > len(aStr) { return "", errors.New(fmt.Sprintf("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(aStr) + start - length + 1 e = len(aStr) + start + 1 } else if start >= 0 && length < 0 { s = start e = len(aStr) + length } else { s = len(aStr) + start e = len(aStr) + length } if s > e { return "", errors.New(fmt.Sprintf("calculated start position greater than end position: %d > %d", s, e)) } if e > len(aStr) { e = len(aStr) } return aStr[s:e], nil }
func Sort(seq interface{}, args ...interface{}) ([]interface{}, error) { seqv := reflect.ValueOf(seq) seqv, isNil := indirect(seqv) if isNil { return nil, errors.New("can't iterate over a nil value") } // Create a list of pairs that will be used to do the sort p := pairList{SortAsc: true} p.Pairs = make([]pair, seqv.Len()) for i, l := range args { dStr, err := cast.ToStringE(l) switch { case i == 0 && err != nil: p.SortByField = "" case i == 0 && err == nil: p.SortByField = dStr case i == 1 && err == nil && dStr == "desc": p.SortAsc = false case i == 1: p.SortAsc = true } } var sorted []interface{} switch seqv.Kind() { case reflect.Array, reflect.Slice: for i := 0; i < seqv.Len(); i++ { p.Pairs[i].Key = reflect.ValueOf(i) p.Pairs[i].Value = seqv.Index(i) } if p.SortByField == "" { p.SortByField = "value" } case reflect.Map: keys := seqv.MapKeys() for i := 0; i < seqv.Len(); i++ { p.Pairs[i].Key = keys[i] p.Pairs[i].Value = seqv.MapIndex(keys[i]) } default: return nil, errors.New("can't sort " + reflect.ValueOf(seq).Type().String()) } sorted = p.sort() return sorted, nil }
// countRunes returns the approximate rune count of the given content. func countRunes(content interface{}) (int, error) { conv, err := cast.ToStringE(content) if err != nil { return 0, fmt.Errorf("Failed to convert content to string: %s", err.Error()) } counter := 0 for _, r := range helpers.StripHTML(conv) { if !helpers.IsWhitespace(r) { counter++ } } return counter, nil }
// humanize returns the humanized form of a single parameter. // If the parameter is either an integer or a string containing an integer // value, the behavior is to add the appropriate ordinal. // Example: "my-first-post" -> "My first post" // Example: "103" -> "103rd" // Example: 52 -> "52nd" func humanize(in interface{}) (string, error) { word, err := cast.ToStringE(in) if err != nil { return "", err } if word == "" { return "", nil } _, ok := in.(int) // original param was literal int value _, err = strconv.Atoi(word) // original param was string containing an int value if ok == true || err == nil { return inflect.Ordinalize(word), nil } return inflect.Humanize(word), 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 } }