can now fill lists

master
Jordan Orelli 9 years ago
parent 981d7978f5
commit 1c82e01937

@ -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
}

@ -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])
}
}

@ -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 {

@ -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))

Loading…
Cancel
Save