Binder

Constants

const (
    DEFAULT_DATE_FORMAT     = "2006-01-02"
    DEFAULT_DATETIME_FORMAT = "2006-01-02 15:04"
)

Variables

var (
    // These are the lookups to find a Binder for any type of data.
    // The most specific binder found will be used (Type before Kind)
    TypeBinders = make(map[reflect.Type]Binder)
    KindBinders = make(map[reflect.Kind]Binder)

    // Applications can add custom time formats to this array, and they will be
    // automatically attempted when binding a time.Time.
    TimeFormats = []string{}

    DateFormat     string
    DateTimeFormat string

    IntBinder = Binder{
        Bind: ValueBinder(func(val string, typ reflect.Type) reflect.Value {
            if len(val) == 0 {
                return reflect.Zero(typ)
            }
            intValue, err := strconv.ParseInt(val, 10, 64)
            if err != nil {
                WARN.Println(err)
                return reflect.Zero(typ)
            }
            pValue := reflect.New(typ)
            pValue.Elem().SetInt(intValue)
            return pValue.Elem()
        }),
        Unbind: func(output map[string]string, key string, val interface{}) {
            output[key] = fmt.Sprintf("%d", val)
        },
    }

    UintBinder = Binder{
        Bind: ValueBinder(func(val string, typ reflect.Type) reflect.Value {
            if len(val) == 0 {
                return reflect.Zero(typ)
            }
            uintValue, err := strconv.ParseUint(val, 10, 64)
            if err != nil {
                WARN.Println(err)
                return reflect.Zero(typ)
            }
            pValue := reflect.New(typ)
            pValue.Elem().SetUint(uintValue)
            return pValue.Elem()
        }),
        Unbind: func(output map[string]string, key string, val interface{}) {
            output[key] = fmt.Sprintf("%d", val)
        },
    }

    FloatBinder = Binder{
        Bind: ValueBinder(func(val string, typ reflect.Type) reflect.Value {
            if len(val) == 0 {
                return reflect.Zero(typ)
            }
            floatValue, err := strconv.ParseFloat(val, 64)
            if err != nil {
                WARN.Println(err)
                return reflect.Zero(typ)
            }
            pValue := reflect.New(typ)
            pValue.Elem().SetFloat(floatValue)
            return pValue.Elem()
        }),
        Unbind: func(output map[string]string, key string, val interface{}) {
            output[key] = fmt.Sprintf("%f", val)
        },
    }

    StringBinder = Binder{
        Bind: ValueBinder(func(val string, typ reflect.Type) reflect.Value {
            return reflect.ValueOf(val)
        }),
        Unbind: func(output map[string]string, name string, val interface{}) {
            output[name] = val.(string)
        },
    }

    // Booleans support a couple different value formats:
    // "true" and "false"
    // "on" and "" (a checkbox)
    // "1" and "0" (why not)
    BoolBinder = Binder{
        Bind: ValueBinder(func(val string, typ reflect.Type) reflect.Value {
            v := strings.TrimSpace(strings.ToLower(val))
            switch v {
            case "true", "on", "1":
                return reflect.ValueOf(true)
            }

            return reflect.ValueOf(false)
        }),
        Unbind: func(output map[string]string, name string, val interface{}) {
            output[name] = fmt.Sprintf("%t", val)
        },
    }

    PointerBinder = Binder{
        Bind: func(params *Params, name string, typ reflect.Type) reflect.Value {
            return Bind(params, name, typ.Elem()).Addr()
        },
        Unbind: func(output map[string]string, name string, val interface{}) {
            Unbind(output, name, reflect.ValueOf(val).Elem().Interface())
        },
    }

    TimeBinder = Binder{
        Bind: ValueBinder(func(val string, typ reflect.Type) reflect.Value {
            for _, f := range TimeFormats {
                if r, err := time.Parse(f, val); err == nil {
                    return reflect.ValueOf(r)
                }
            }
            return reflect.Zero(typ)
        }),
        Unbind: func(output map[string]string, name string, val interface{}) {
            var (
                t       = val.(time.Time)
                format  = DateTimeFormat
                h, m, s = t.Clock()
            )
            if h == 0 && m == 0 && s == 0 {
                format = DateFormat
            }
            output[name] = t.Format(format)
        },
    }

    MapBinder = Binder{
        Bind:   bindMap,
        Unbind: unbindMap,
    }
)

func Bind

func Bind(params *Params, name string, typ reflect.Type) reflect.Value

Bind takes the name and type of the desired parameter and constructs it from one or more values from Params. Returns the zero value of the type upon any sort of failure.

func BindFile

func BindFile(fileHeader *multipart.FileHeader, typ reflect.Type) reflect.Value

func BindValue

func BindValue(val string, typ reflect.Type) reflect.Value

func Unbind

func Unbind(output map[string]string, name string, val interface{})

func ValueBinder

func ValueBinder(f func(value string, typ reflect.Type) reflect.Value) func(*Params, string, reflect.Type) reflect.Value

An adapter for easily making one-key-value binders.

type Binder

type Binder struct {
    // Bind takes the name and type of the desired parameter and constructs it
    // from one or more values from Params.
    //
    // Example
    //
    // Request:
    //   url?id=123&ol[0]=1&ol[1]=2&ul[]=str&ul[]=array&user.Name=rob
    //
    // Action:
    //   Example.Action(id int, ol []int, ul []string, user User)
    //
    // Calls:
    //   Bind(params, "id", int): 123
    //   Bind(params, "ol", []int): {1, 2}
    //   Bind(params, "ul", []string): {"str", "array"}
    //   Bind(params, "user", User): User{Name:"rob"}
    //
    // Note that only exported struct fields may be bound.
    Bind func(params *Params, name string, typ reflect.Type) reflect.Value

    // Unbind serializes a given value to one or more URL parameters of the given
    // name.
    Unbind func(output map[string]string, name string, val interface{})
}

A Binder translates between string parameters and Go data structures.