Skip to content

Commit

Permalink
Merge pull request #292 from hairyhenderson/add-conv-tostring-func
Browse files Browse the repository at this point in the history
Adding conv.ToString function
  • Loading branch information
hairyhenderson authored Apr 19, 2018
2 parents 2aea441 + b061d82 commit 3813bd3
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 15 deletions.
22 changes: 8 additions & 14 deletions conv/conv.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func Join(in interface{}, sep string) string {
if ok {
b := make([]string, len(a))
for i := range a {
b[i] = toString(a[i])
b[i] = ToString(a[i])
}
return strings.Join(b, sep)
}
Expand Down Expand Up @@ -77,7 +77,8 @@ func Has(in interface{}, key string) bool {
return false
}

func toString(in interface{}) string {
// ToString -
func ToString(in interface{}) string {
if in == nil {
return "nil"
}
Expand All @@ -87,19 +88,12 @@ func toString(in interface{}) string {
if s, ok := in.(fmt.Stringer); ok {
return s.String()
}
val := reflect.Indirect(reflect.ValueOf(in))
switch val.Kind() {
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
return strconv.FormatInt(val.Int(), 10)
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint, reflect.Uint64:
return strconv.FormatUint(val.Uint(), 10)
case reflect.Float32, reflect.Float64:
return strconv.FormatFloat(val.Float(), 'f', -1, 64)
case reflect.Bool:
return strconv.FormatBool(val.Bool())
default:
return fmt.Sprintf("%s", in)

v, ok := printableValue(reflect.ValueOf(in))
if ok {
in = v
}
return fmt.Sprint(in)
}

// MustParseInt - wrapper for strconv.ParseInt that returns 0 in the case of error
Expand Down
46 changes: 46 additions & 0 deletions conv/conv_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package conv

import (
"fmt"
"math"
"testing"

Expand Down Expand Up @@ -167,3 +168,48 @@ func TestToFloat64s(t *testing.T) {
assert.Equal(t, []float64{}, ToFloat64s())
assert.Equal(t, []float64{0, 1.0, 2.0, math.Pi, 4.0}, ToFloat64s(nil, true, "2", math.Pi, uint8(4)))
}

type foo struct {
val string
}

func (f foo) String() string {
return f.val
}

func TestToString(t *testing.T) {
var p *string
f := "foo"
p = &f

var n *string

data := []struct {
in interface{}
out string
}{
{nil, "nil"},
{"", ""},
{"foo", "foo"},
{true, "true"},
{42, "42"},
{3.14, "3.14"},
{-127, "-127"},
{0xFF, "255"},
{uint8(42), "42"},
{math.Pi, "3.141592653589793"},
{math.NaN(), "NaN"},
{math.Inf(1), "+Inf"},
{math.Inf(-1), "-Inf"},
{foo{"bar"}, "bar"},
{p, "foo"},
{fmt.Errorf("hi"), "hi"},
{n, "<nil>"},
}

for _, d := range data {
t.Run(fmt.Sprintf("%T/%#v == %s", d.in, d.in, d.out), func(t *testing.T) {
assert.Equal(t, d.out, ToString(d.in))
})
}
}
45 changes: 45 additions & 0 deletions conv/evalargs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package conv

// stolen from the Go standard library, text/template package.
import (
"fmt"
"reflect"
)

var (
errorType = reflect.TypeOf((*error)(nil)).Elem()
fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
)

// printableValue returns the, possibly indirected, interface value inside v that
// is best for a call to formatted printer.
func printableValue(v reflect.Value) (interface{}, bool) {
if v.Kind() == reflect.Ptr {
v, _ = indirect(v) // fmt.Fprint handles nil.
}
if !v.IsValid() {
return "<no value>", true
}

if !v.Type().Implements(errorType) && !v.Type().Implements(fmtStringerType) {
if v.CanAddr() && (reflect.PtrTo(v.Type()).Implements(errorType) || reflect.PtrTo(v.Type()).Implements(fmtStringerType)) {
v = v.Addr()
} else {
switch v.Kind() {
case reflect.Chan, reflect.Func:
return nil, false
}
}
}
return v.Interface(), true
}

// indirect returns the item at the end of indirection, and a bool to indicate if it's nil.
func indirect(v reflect.Value) (rv reflect.Value, isNil bool) {
for ; v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface; v = v.Elem() {
if v.IsNil() {
return v, true
}
}
return v, false
}
6 changes: 5 additions & 1 deletion docs/content/functions/conv.md
Original file line number Diff line number Diff line change
Expand Up @@ -232,4 +232,8 @@ Converts the input to a `float64`

## `conv.ToFloat64s`

Converts the inputs to an array of `float64`s
Converts the inputs to an array of `float64`s

## `conv.ToString`

Converts the input (of any type) to a `string`
25 changes: 25 additions & 0 deletions funcs/conv.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,57 +32,82 @@ func AddConvFuncs(f map[string]interface{}) {
// ConvFuncs -
type ConvFuncs struct{}

// Bool -
func (f *ConvFuncs) Bool(s string) bool {
return conv.Bool(s)
}

// Slice -
func (f *ConvFuncs) Slice(args ...interface{}) []interface{} {
return conv.Slice(args...)
}

// Join -
func (f *ConvFuncs) Join(in interface{}, sep string) string {
return conv.Join(in, sep)
}

// Has -
func (f *ConvFuncs) Has(in interface{}, key string) bool {
return conv.Has(in, key)
}

// ParseInt -
func (f *ConvFuncs) ParseInt(s string, base, bitSize int) int64 {
return conv.MustParseInt(s, base, bitSize)
}

// ParseFloat -
func (f *ConvFuncs) ParseFloat(s string, bitSize int) float64 {
return conv.MustParseFloat(s, bitSize)
}

// ParseUint -
func (f *ConvFuncs) ParseUint(s string, base, bitSize int) uint64 {
return conv.MustParseUint(s, base, bitSize)
}

// Atoi -
func (f *ConvFuncs) Atoi(s string) int {
return conv.MustAtoi(s)
}

// URL -
func (f *ConvFuncs) URL(s string) (*url.URL, error) {
return url.Parse(s)
}

// ToInt64 -
func (f *ConvFuncs) ToInt64(in interface{}) int64 {
return conv.ToInt64(in)
}

// ToInt -
func (f *ConvFuncs) ToInt(in interface{}) int {
return conv.ToInt(in)
}

// ToInt64s -
func (f *ConvFuncs) ToInt64s(in ...interface{}) []int64 {
return conv.ToInt64s(in)
}

// ToInts -
func (f *ConvFuncs) ToInts(in ...interface{}) []int {
return conv.ToInts(in)
}

// ToFloat64 -
func (f *ConvFuncs) ToFloat64(in interface{}) float64 {
return conv.ToFloat64(in)
}

// ToFloat64s -
func (f *ConvFuncs) ToFloat64s(in ...interface{}) []float64 {
return conv.ToFloat64s(in)
}

// ToString -
func (f *ConvFuncs) ToString(in interface{}) string {
return conv.ToString(in)
}

0 comments on commit 3813bd3

Please sign in to comment.