1
0
mirror of https://github.com/danog/liquid.git synced 2025-01-22 23:01:16 +01:00

Convert -> map[string]

This commit is contained in:
Oliver Steele 2017-06-30 08:03:55 -04:00
parent 8ea72e4300
commit 767f1f421b
3 changed files with 100 additions and 46 deletions

View File

@ -5,12 +5,21 @@ import (
"reflect"
"strconv"
"time"
"github.com/jeffjen/datefmt"
)
var timeType = reflect.TypeOf(time.Now())
func conversionError(modifier string, value interface{}, typ reflect.Type) error {
if modifier != "" {
modifier += " "
}
switch ref := value.(type) {
case reflect.Value:
value = ref.Interface()
}
return genericErrorf("can't convert %s%T(%v) to type %s", modifier, value, value, typ)
}
// Convert value to the type. This is a more aggressive conversion, that will
// recursively create new map and slice values as necessary. It doesn't
// handle circular references.
@ -46,16 +55,23 @@ func Convert(value interface{}, target reflect.Type) (interface{}, error) {
case reflect.Map:
out := reflect.MakeMap(target)
for _, key := range r.MapKeys() {
if target.Key().Kind() == reflect.String {
key = reflect.ValueOf(fmt.Sprint(key))
}
if !key.Type().ConvertibleTo(target.Key()) {
return nil, genericErrorf("generic.Convert can't convert %#v map key %#v to type %s", value, key.Interface(), target.Key())
return nil, conversionError("map key", key, target.Key())
}
key = key.Convert(target.Key())
value := r.MapIndex(key)
if !value.Type().ConvertibleTo(target.Key()) {
return nil, genericErrorf("generic.Convert can't convert %#v map value %#v to type %s", value, value.Interface(), target.Elem())
if target.Elem().Kind() == reflect.String {
value = reflect.ValueOf(fmt.Sprint(value))
}
if !value.Type().ConvertibleTo(target.Elem()) {
return nil, conversionError("map value", value, target.Elem())
}
out.SetMapIndex(key, value.Convert(target.Elem()))
}
return out.Interface(), nil
case reflect.Slice:
if r.Kind() != reflect.Array && r.Kind() != reflect.Slice {
break
@ -70,7 +86,7 @@ func Convert(value interface{}, target reflect.Type) (interface{}, error) {
}
return out.Interface(), nil
}
return nil, genericErrorf("generic.Convert can't convert %#v of type %s / kind %s to type %s", value, r.Type(), r.Kind(), target)
return nil, conversionError("", value, target)
}
// MustConvert wraps Convert, but panics on error.
@ -90,43 +106,3 @@ func MustConvertItem(item interface{}, array []interface{}) interface{} {
}
return item
}
var dateFormats = []string{
"%Y-%m-%d %H:%M:%S %Z",
}
var dateLayouts = []string{
"2006-01-02 15:04:05 -07:00",
"2006-01-02 15:04:05 -0700",
"2006-01-02 15:04:05 -7",
"2006-01-02 15:04:05",
"2006-01-02 15:04",
"2006-01-02",
"January 2, 2006",
"January 2 2006",
"Jan 2, 2006",
"Jan 2 2006",
}
// ParseTime tries a few heuristics to parse a date from a string
func ParseTime(s string) (time.Time, error) {
if s == "now" {
return time.Now(), nil
}
for _, layout := range dateLayouts {
// fmt.Printf("%s\n%s\n\n", time.Now().Format(layout), s)
t, err := time.Parse(layout, s)
if err == nil {
return t, nil
}
}
for _, format := range dateFormats {
// xx, _ := datefmt.Strftime(format, time.Now())
// fmt.Printf("%s\n%s\n\n", xx, s)
t, err := datefmt.Strptime(format, s)
if err == nil {
return t, nil
}
}
return time.Unix(0, 0), genericErrorf("can't convert %s to a time", s)
}

View File

@ -73,6 +73,34 @@ func TestConvert(t *testing.T) {
})
}
}
func TestConvertMap(t *testing.T) {
m := map[interface{}]interface{}{"key": "value"}
typ := reflect.TypeOf(map[string]string{})
a, err := Convert(m, typ)
require.NoError(t, err)
switch a := a.(type) {
case map[string]string:
require.Len(t, a, 1)
require.Equal(t, "value", a["key"])
default:
require.Equal(t, typ.String(), reflect.TypeOf(a).String())
}
}
func TestConvertMapSynonym(t *testing.T) {
type VariableMap map[interface{}]interface{}
m := VariableMap{"key": "value"}
typ := reflect.TypeOf(map[string]string{})
a, err := Convert(m, typ)
require.NoError(t, err)
switch a := a.(type) {
case map[string]string:
require.Len(t, a, 1)
require.Equal(t, "value", a["key"])
default:
require.Equal(t, typ.String(), reflect.TypeOf(a).String())
}
}
func TestEqual(t *testing.T) {
for i, test := range eqTests {

50
generics/time.go Normal file
View File

@ -0,0 +1,50 @@
package generics
import (
"reflect"
"time"
"github.com/jeffjen/datefmt"
)
var zeroTime = time.Unix(0, 0)
var dateFormats = []string{
"%Y-%m-%d %H:%M:%S %Z",
}
var dateLayouts = []string{
"2006-01-02 15:04:05 -07:00",
"2006-01-02 15:04:05 -0700",
"2006-01-02 15:04:05 -7",
"2006-01-02 15:04:05",
"2006-01-02 15:04",
"2006-01-02",
"January 2, 2006",
"January 2 2006",
"Jan 2, 2006",
"Jan 2 2006",
}
// ParseTime tries a few heuristics to parse a date from a string
func ParseTime(s string) (time.Time, error) {
if s == "now" {
return time.Now(), nil
}
for _, layout := range dateLayouts {
// fmt.Printf("%s\n%s\n\n", time.Now().Format(layout), s)
t, err := time.Parse(layout, s)
if err == nil {
return t, nil
}
}
for _, format := range dateFormats {
// xx, _ := datefmt.Strftime(format, time.Now())
// fmt.Printf("%s\n%s\n\n", xx, s)
t, err := datefmt.Strptime(format, s)
if err == nil {
return t, nil
}
}
return zeroTime, conversionError("", s, reflect.TypeOf(zeroTime))
}