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
|
||||
|
||||
# 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
|
||||
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
|
||||
// given by `out`.
|
||||
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 {
|
||||
// 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
|
||||
redecode := true
|
||||
|
||||
@ -574,3 +587,12 @@ func (d *decoder) decodeStruct(name string, node ast.Node, result reflect.Value)
|
||||
|
||||
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"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/hcl/hcl/ast"
|
||||
)
|
||||
|
||||
func TestDecode_interface(t *testing.T) {
|
||||
@ -586,3 +588,77 @@ func TestDecode_intString(t *testing.T) {
|
||||
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…
Reference in New Issue
Block a user