Skip to content

Commit

Permalink
Added support for custom unmarshalling.
Browse files Browse the repository at this point in the history
  • Loading branch information
eddieowens committed Apr 27, 2020
1 parent a8d7dc5 commit 7c9a36a
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 4 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ require (
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/sergi/go-diff v1.0.0
github.com/spf13/pflag v1.0.2
github.com/stretchr/testify v1.2.2 // indirect
github.com/stretchr/testify v1.5.1
github.com/zclconf/go-cty v1.2.0
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734
golang.org/x/sys v0.0.0-20190502175342-a43fa875dd82 // indirect
Expand Down
8 changes: 8 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ github.com/apparentlymart/go-textseg v1.0.0 h1:rRmlIsPEEhUTIKQb7T++Nz/A5Q6C9IuX2
github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk=
github.com/apparentlymart/go-textseg/v12 v12.0.0 h1:bNEQyAGak9tojivJNkoqWErVCQbjdL7GzRt3F8NvfJ0=
github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
Expand All @@ -28,8 +29,12 @@ github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/spf13/pflag v1.0.2 h1:Fy0orTDgHdbnzHcsOgfCN4LtHf0ec3wwtiwJqwvf3Gc=
github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
github.com/zclconf/go-cty v1.2.0 h1:sPHsy7ADcIZQP3vILvTjrh74ZA175TFP5vqiNK1UmlI=
github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8=
Expand All @@ -49,5 +54,8 @@ golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
16 changes: 16 additions & 0 deletions gohcl/decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ func DecodeBody(body hcl.Body, ctx *hcl.EvalContext, val interface{}) hcl.Diagno
return decodeBodyToValue(body, ctx, rv.Elem())
}

type Unmarshaler interface {
UnmarshalHCL(block *hcl.Block, ctx *hcl.EvalContext) hcl.Diagnostics
}

func decodeBodyToValue(body hcl.Body, ctx *hcl.EvalContext, val reflect.Value) hcl.Diagnostics {
et := val.Type()
switch et.Kind() {
Expand Down Expand Up @@ -246,6 +250,18 @@ func decodeBlockToValue(block *hcl.Block, ctx *hcl.EvalContext, v reflect.Value)

ty := v.Type()

if v.CanInterface() {
if unm, ok := v.Interface().(Unmarshaler); ok {
return unm.UnmarshalHCL(block, ctx)
}
}

if v.CanAddr() && v.CanInterface() {
if unm, ok := v.Addr().Interface().(Unmarshaler); ok {
return unm.UnmarshalHCL(block, ctx)
}
}

switch {
case blockType.AssignableTo(ty):
v.Elem().Set(reflect.ValueOf(block))
Expand Down
64 changes: 61 additions & 3 deletions gohcl/decode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,73 @@ package gohcl
import (
"encoding/json"
"fmt"
"reflect"
"testing"

"github.com/davecgh/go-spew/spew"
"github.com/kage-cloud/hcl/v2"
hclJSON "github.com/kage-cloud/hcl/v2/json"
"github.com/stretchr/testify/assert"
"github.com/zclconf/go-cty/cty"
"reflect"
"testing"
)

type withTwoAttributes struct {
A string `hcl:"a,optional" json:"a"`
B string `hcl:"b,optional" json:"b"`
}

func (w *withTwoAttributes) UnmarshalHCL(block *hcl.Block, ctx *hcl.EvalContext) hcl.Diagnostics {
if diags := DecodeBody(block.Body, ctx, w); diags != nil && diags.HasErrors() {
return diags
}

t := w.A
w.A = w.B
w.B = t

return nil
}

type testStruct struct {
Attributes []withTwoAttributes `hcl:"attrs,block" json:"attrs"`
}

func TestUnmarshal(t *testing.T) {
given := &testStruct{
Attributes: []withTwoAttributes{
{
A: "hello",
B: "world",
},
},
}

expected := given

b, err := json.Marshal(given)
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}

expected.Attributes[0].A = "world"
expected.Attributes[0].B = "hello"

f, diags := hclJSON.Parse(b, "test.json")
if diags != nil && diags.HasErrors() {
fmt.Println(diags.Error())
t.FailNow()
}

actual := new(testStruct)
diags = DecodeBody(f.Body, nil, actual)
if diags != nil && diags.HasErrors() {
fmt.Println(diags.Error())
t.FailNow()
}

assert.Equal(t, expected, actual)
}

func TestDecodeBody(t *testing.T) {
deepEquals := func(other interface{}) func(v interface{}) bool {
return func(v interface{}) bool {
Expand Down

0 comments on commit 7c9a36a

Please sign in to comment.