From 1c82e0193799eb5c9dddcdcd71725418f7f64211 Mon Sep 17 00:00:00 2001 From: Jordan Orelli Date: Tue, 14 Jul 2015 17:10:29 -0400 Subject: [PATCH] can now fill lists --- list.go | 39 +++++++++++++++++++++++++++++++++++++++ list_test.go | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ node.go | 2 +- object.go | 8 +++++--- 4 files changed, 94 insertions(+), 4 deletions(-) create mode 100644 list.go create mode 100644 list_test.go diff --git a/list.go b/list.go new file mode 100644 index 0000000..2d88829 --- /dev/null +++ b/list.go @@ -0,0 +1,39 @@ +package moon + +import ( + "fmt" + "reflect" +) + +type List []interface{} + +func (l List) fillValue(v reflect.Value) error { + if v.Kind() != reflect.Slice { + return fmt.Errorf("moon List can only fillValue to a slice, saw %v (%v)", v.Type(), v.Kind()) + } + if v.IsNil() { + v.Set(reflect.MakeSlice(v.Type(), len(l), cap(l))) + } + for idx, item := range l { + dv := v.Index(idx) + + switch t_sv := item.(type) { + case *Object: + if err := t_sv.fillValue(dv); err != nil { + return err + } + case List: + if err := t_sv.fillValue(dv); err != nil { + return err + } + default: + sv := reflect.ValueOf(item) + if dv.Type().AssignableTo(sv.Type()) { + return fmt.Errorf("can assign") + } else { + return fmt.Errorf("unable to assign element %d: source type %v is not assignable to destination type %v", idx, sv.Type(), dv.Type()) + } + } + } + return nil +} diff --git a/list_test.go b/list_test.go new file mode 100644 index 0000000..1e441c2 --- /dev/null +++ b/list_test.go @@ -0,0 +1,49 @@ +package moon + +import ( + "testing" +) + +func TestFillList(t *testing.T) { + doc, err := ReadString(` + # yay for lists + servers: [ + {hostname: dev.example.com; label: dev} + {hostname: prod.example.com; label: prod} + ] + `) + if err != nil { + t.Error(err) + return + } + var config struct { + Servers []struct { + Hostname string `name: hostname; required: true` + Label string `name: label; required: true` + } `name: servers` + } + if err := doc.Fill(&config); err != nil { + t.Error(err) + return + } + if config.Servers == nil { + t.Error("servers is nil for some reason") + return + } + if len(config.Servers) != 2 { + t.Errorf("expected 2 servers, saw %d", len(config.Servers)) + return + } + if config.Servers[0].Hostname != "dev.example.com" { + t.Errorf("wut lol %v", config.Servers[0]) + } + if config.Servers[0].Label != "dev" { + t.Errorf("wut lol %v", config.Servers[0]) + } + if config.Servers[1].Hostname != "prod.example.com" { + t.Errorf("wut 1 lol %v", config.Servers[1]) + } + if config.Servers[1].Label != "prod" { + t.Errorf("wut 2 lol %v", config.Servers[1]) + } +} diff --git a/node.go b/node.go index 48b76f5..a4d30a2 100644 --- a/node.go +++ b/node.go @@ -388,7 +388,7 @@ func (l *listNode) pretty(w io.Writer, prefix string) error { } func (l *listNode) eval(ctx *context) (interface{}, error) { - out := make([]interface{}, 0, len(*l)) + out := make(List, 0, len(*l)) for _, n := range *l { v, err := n.eval(ctx) if err != nil { diff --git a/object.go b/object.go index d4475a6..302d9f1 100644 --- a/object.go +++ b/object.go @@ -147,7 +147,7 @@ func (o *Object) fillValue(dv reflect.Value) error { if dv.IsNil() { dv.Set(reflect.New(dv.Type().Elem())) } - dv = reflect.Indirect(dv) + dv = dv.Elem() default: return fmt.Errorf("moon object can only fillValue to a struct value, saw %v (%v)", dv.Type(), dv.Kind()) } @@ -180,6 +180,8 @@ func (o *Object) fillValue(dv reflect.Value) error { switch t_ov := ov.(type) { case *Object: return t_ov.fillValue(fv) + case List: + return t_ov.fillValue(fv) default: if !fv.Type().AssignableTo(reflect.TypeOf(ov)) { return fmt.Errorf("unable to assign field %s: source type %v is not assignable to destination type %v", req.name, reflect.TypeOf(ov), fv.Type()) @@ -209,9 +211,9 @@ func seekValue(fullpath string, parts []string, root interface{}) (interface{}, head, tail := parts[0], parts[1:] n, err := strconv.Atoi(head) if err == nil { - l, ok := root.([]interface{}) + l, ok := root.(List) if !ok { - return nil, fmt.Errorf("can only index a []interface{}, root is %s", reflect.TypeOf(root)) + return nil, fmt.Errorf("can only index a List, root is %s", reflect.TypeOf(root)) } if n >= len(l) { return nil, fmt.Errorf("path %s is out of bounds, can't get the %d index from a slice of len %d", fullpath, n, len(l))