Skip to content

Commit

Permalink
Support slice-of-pointer value types.
Browse files Browse the repository at this point in the history
  • Loading branch information
Tony Spataro committed Dec 2, 2016
1 parent 32b8759 commit 9580b90
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 14 deletions.
2 changes: 1 addition & 1 deletion flatpack.go
Expand Up @@ -38,7 +38,7 @@ var DataSource Getter = &processEnvironment{os.LookupEnv}
//
// NOTE: flatpack currently lacks a public non-singleton interface, but it
// would be easy to add by simply exporting flatpack.new() and
// flatpack.unmarshaller.
// declaring an Unmarshaller interface.
func Unmarshal(dest interface{}) error {
return new(DataSource).Unmarshal(dest)
}
17 changes: 12 additions & 5 deletions implementation.go
Expand Up @@ -115,7 +115,7 @@ func (f implementation) assign(dest reflect.Value, source string, name Key) (err
}
default:
// should be unreachable due to validation in read()
panic("case should be unreachable; bug in flatpack.unmarshaller.read()")
panic(fmt.Errorf("flatpack: unreachable code in assign(); bug in read()? (kind=%s)", kind))
}

return
Expand All @@ -131,7 +131,8 @@ func (f implementation) assign(dest reflect.Value, source string, name Key) (err
// Return the number of fields that were set.
func (f implementation) read(name Key, value reflect.Value) (int, error) {
count := 0
kind := value.Type().Kind()
vt := value.Type()
kind := vt.Kind()

var got string
var err error
Expand All @@ -146,16 +147,22 @@ func (f implementation) read(name Key, value reflect.Value) (int, error) {
err = f.assign(value, got, name)
count++
}
case reflect.Array, reflect.Slice:
case reflect.Slice:
got, err = f.source.Get(name)
if err == nil && got != "" {
var raw []interface{}
err = json.Unmarshal([]byte(got), &raw)
if err == nil {
value.Set(reflect.MakeSlice(value.Type(), len(raw), len(raw)))
vte := value.Type().Elem()
value.Set(reflect.MakeSlice(vt, len(raw), len(raw)))
for i, elem := range raw {
if err == nil {
err = f.assign(value.Index(i), fmt.Sprintf("%v", elem), name)
vi := value.Index(i)
if vte.Kind() == reflect.Ptr {
vi.Set(reflect.New(vte.Elem()))
vi = vi.Elem()
}
err = f.assign(vi, fmt.Sprintf("%v", elem), name)
count++
}
}
Expand Down
27 changes: 19 additions & 8 deletions implementation_test.go
Expand Up @@ -13,7 +13,9 @@ type simple struct {
Baz struct {
Foo string
Bar int
Baz float64
}
Quux []int
}

type pointery struct {
Expand All @@ -23,6 +25,7 @@ type pointery struct {
Bar *struct {
Foo string
}
Baz []*int
}

// Test that we avoid a new panic introduced in go 1.5:
Expand All @@ -43,29 +46,34 @@ var _ = Describe("implementation", func() {
})

Describe(".Unmarshal()", func() {
It("handles missing keys", func() {
It("handles strings and numbers", func() {
fx := simple{}
env := map[string]string{
"FOO": "foo",
"BAZ_FOO": "baz foo",
"BAZ_BAR": "42",
"BAZ_BAZ": "3.14159",
}
it := implementation{stubEnvironment(env)}
err := it.Unmarshal(&fx)
Expect(err).To(Succeed())
Expect(fx.Foo).To(Equal("foo"))
Expect(fx.Baz.Foo).To(Equal("baz foo"))
Expect(fx.Baz.Bar).To(Equal(42))
Expect(fx.Baz.Baz).To(Equal(3.14159))
})

It("handles nested structs", func() {
fx := pointery{}
It("handles slices", func() {
fx := simple{}
env := map[string]string{
"FOO_FOO": "foo foo",
"BAR_FOO": "bar foo",
"BAR": `["foo", "bar"]`,
"QUUX": `[1,2,3]`,
}
it := implementation{stubEnvironment(env)}
err := it.Unmarshal(&fx)
Expect(err).To(Succeed())
Expect(fx.Foo.Foo).To(Equal("foo foo"))
Expect(fx.Bar).NotTo(BeNil())
Expect(fx.Bar.Foo).To(Equal("bar foo"))
Expect(fx.Bar).To(Equal([]string{"foo", "bar"}))
Expect(fx.Quux).To(Equal([]int{1, 2, 3}))
})

It("allocates pointers when needed", func() {
Expand All @@ -81,11 +89,14 @@ var _ = Describe("implementation", func() {
env = map[string]string{
"FOO_FOO": "foo foo",
"BAR_FOO": "bar foo",
"BAZ": `[1,2,3]`,
}
it = implementation{stubEnvironment(env)}
err = it.Unmarshal(&fx)
Expect(err).To(Succeed())
Expect(fx.Bar).NotTo(BeNil())
one, two, three := 1, 2, 3
Expect(fx.Baz).To(Equal([]*int{&one, &two, &three}))
})

Context("error reporting", func() {
Expand Down

0 comments on commit 9580b90

Please sign in to comment.