Merge pull request #72 from savaki/master
adds facility for deferred Decode similar to how json.RawMessage enables deferred Unmarshal
This commit is contained in:
commit
e3dcd7fc89
6
.gitignore
vendored
6
.gitignore
vendored
@ -1 +1,7 @@
|
|||||||
y.output
|
y.output
|
||||||
|
|
||||||
|
# ignore intellij files
|
||||||
|
.idea
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
*.iws
|
||||||
|
22
decoder.go
22
decoder.go
@ -15,6 +15,11 @@ import (
|
|||||||
// This is the tag to use with structures to have settings for HCL
|
// This is the tag to use with structures to have settings for HCL
|
||||||
const tagName = "hcl"
|
const tagName = "hcl"
|
||||||
|
|
||||||
|
var (
|
||||||
|
// nodeType holds a reference to the type of ast.Node
|
||||||
|
nodeType reflect.Type = findNodeType()
|
||||||
|
)
|
||||||
|
|
||||||
// Decode reads the given input and decodes it into the structure
|
// Decode reads the given input and decodes it into the structure
|
||||||
// given by `out`.
|
// given by `out`.
|
||||||
func Decode(out interface{}, in string) error {
|
func Decode(out interface{}, in string) error {
|
||||||
@ -158,6 +163,14 @@ func (d *decoder) decodeInt(name string, node ast.Node, result reflect.Value) er
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *decoder) decodeInterface(name string, node ast.Node, result reflect.Value) error {
|
func (d *decoder) decodeInterface(name string, node ast.Node, result reflect.Value) error {
|
||||||
|
// When we see an ast.Node, we retain the value to enable deferred decoding.
|
||||||
|
// Very useful in situations where we want to preserve ast.Node information
|
||||||
|
// like Pos
|
||||||
|
if result.Type() == nodeType && result.CanSet() {
|
||||||
|
result.Set(reflect.ValueOf(node))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
var set reflect.Value
|
var set reflect.Value
|
||||||
redecode := true
|
redecode := true
|
||||||
|
|
||||||
@ -574,3 +587,12 @@ func (d *decoder) decodeStruct(name string, node ast.Node, result reflect.Value)
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// findNodeType returns the type of ast.Node
|
||||||
|
func findNodeType() reflect.Type {
|
||||||
|
var nodeContainer struct {
|
||||||
|
Node ast.Node
|
||||||
|
}
|
||||||
|
value := reflect.ValueOf(nodeContainer).FieldByName("Node")
|
||||||
|
return value.Type()
|
||||||
|
}
|
||||||
|
@ -5,6 +5,8 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/hcl/hcl/ast"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDecode_interface(t *testing.T) {
|
func TestDecode_interface(t *testing.T) {
|
||||||
@ -586,3 +588,77 @@ func TestDecode_intString(t *testing.T) {
|
|||||||
t.Fatalf("bad: %#v", value.Count)
|
t.Fatalf("bad: %#v", value.Count)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDecode_Node(t *testing.T) {
|
||||||
|
// given
|
||||||
|
var value struct {
|
||||||
|
Content ast.Node
|
||||||
|
Nested struct {
|
||||||
|
Content ast.Node
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
content := `
|
||||||
|
content {
|
||||||
|
hello = "world"
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
// when
|
||||||
|
err := Decode(&value, content)
|
||||||
|
|
||||||
|
// then
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unable to decode content, %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify ast.Node can be decoded later
|
||||||
|
var v map[string]interface{}
|
||||||
|
err = DecodeObject(&v, value.Content)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unable to decode content, %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if v["hello"] != "world" {
|
||||||
|
t.Errorf("expected mapping to be returned")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDecode_NestedNode(t *testing.T) {
|
||||||
|
// given
|
||||||
|
var value struct {
|
||||||
|
Nested struct {
|
||||||
|
Content ast.Node
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
content := `
|
||||||
|
nested "content" {
|
||||||
|
hello = "world"
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
// when
|
||||||
|
err := Decode(&value, content)
|
||||||
|
|
||||||
|
// then
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unable to decode content, %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify ast.Node can be decoded later
|
||||||
|
var v map[string]interface{}
|
||||||
|
err = DecodeObject(&v, value.Nested.Content)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unable to decode content, %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if v["hello"] != "world" {
|
||||||
|
t.Errorf("expected mapping to be returned")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user