mirror of
https://github.com/danog/liquid.git
synced 2025-01-23 02:11:16 +01:00
Convert -> map[string]
This commit is contained in:
parent
8ea72e4300
commit
767f1f421b
@ -5,12 +5,21 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jeffjen/datefmt"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var timeType = reflect.TypeOf(time.Now())
|
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
|
// 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
|
// recursively create new map and slice values as necessary. It doesn't
|
||||||
// handle circular references.
|
// handle circular references.
|
||||||
@ -46,16 +55,23 @@ func Convert(value interface{}, target reflect.Type) (interface{}, error) {
|
|||||||
case reflect.Map:
|
case reflect.Map:
|
||||||
out := reflect.MakeMap(target)
|
out := reflect.MakeMap(target)
|
||||||
for _, key := range r.MapKeys() {
|
for _, key := range r.MapKeys() {
|
||||||
|
if target.Key().Kind() == reflect.String {
|
||||||
|
key = reflect.ValueOf(fmt.Sprint(key))
|
||||||
|
}
|
||||||
if !key.Type().ConvertibleTo(target.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())
|
key = key.Convert(target.Key())
|
||||||
value := r.MapIndex(key)
|
value := r.MapIndex(key)
|
||||||
if !value.Type().ConvertibleTo(target.Key()) {
|
if target.Elem().Kind() == reflect.String {
|
||||||
return nil, genericErrorf("generic.Convert can't convert %#v map value %#v to type %s", value, value.Interface(), target.Elem())
|
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()))
|
out.SetMapIndex(key, value.Convert(target.Elem()))
|
||||||
}
|
}
|
||||||
|
return out.Interface(), nil
|
||||||
case reflect.Slice:
|
case reflect.Slice:
|
||||||
if r.Kind() != reflect.Array && r.Kind() != reflect.Slice {
|
if r.Kind() != reflect.Array && r.Kind() != reflect.Slice {
|
||||||
break
|
break
|
||||||
@ -70,7 +86,7 @@ func Convert(value interface{}, target reflect.Type) (interface{}, error) {
|
|||||||
}
|
}
|
||||||
return out.Interface(), nil
|
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.
|
// MustConvert wraps Convert, but panics on error.
|
||||||
@ -90,43 +106,3 @@ func MustConvertItem(item interface{}, array []interface{}) interface{} {
|
|||||||
}
|
}
|
||||||
return item
|
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)
|
|
||||||
}
|
|
||||||
|
@ -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) {
|
func TestEqual(t *testing.T) {
|
||||||
for i, test := range eqTests {
|
for i, test := range eqTests {
|
||||||
|
50
generics/time.go
Normal file
50
generics/time.go
Normal 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))
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user