Skip to content

Commit

Permalink
feat: comment annotation on struct
Browse files Browse the repository at this point in the history
Signed-off-by: Yvonnick Esnault <[email protected]>
  • Loading branch information
yesnault committed Sep 11, 2017
1 parent 1d6b12b commit c58d639
Show file tree
Hide file tree
Showing 8 changed files with 91 additions and 17 deletions.
11 changes: 8 additions & 3 deletions marshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

type tomlOpts struct {
name string
comment *string
include bool
omitempty bool
}
Expand Down Expand Up @@ -147,7 +148,7 @@ func valueToTree(mtype reflect.Type, mval reflect.Value) (*Tree, error) {
if err != nil {
return nil, err
}
tval.Set(opts.name, val)
tval.Set(opts.name, opts.comment, val)
}
}
case reflect.Map:
Expand All @@ -157,7 +158,7 @@ func valueToTree(mtype reflect.Type, mval reflect.Value) (*Tree, error) {
if err != nil {
return nil, err
}
tval.Set(key.String(), val)
tval.Set(key.String(), nil, val)
}
}
return tval, nil
Expand Down Expand Up @@ -448,7 +449,11 @@ func unwrapPointer(mtype reflect.Type, tval interface{}) (reflect.Value, error)
func tomlOptions(vf reflect.StructField) tomlOpts {
tag := vf.Tag.Get("toml")
parse := strings.Split(tag, ",")
result := tomlOpts{vf.Name, true, false}
var comment *string
if c := vf.Tag.Get("comment"); c != "" {
comment = &c
}
result := tomlOpts{vf.Name, comment, true, false}
if parse[0] != "" {
if parse[0] == "-" && len(parse) == 1 {
result.include = false
Expand Down
44 changes: 44 additions & 0 deletions marshal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -598,3 +598,47 @@ func TestNestedCustomMarshaler(t *testing.T) {
t.Errorf("Bad nested custom marshaler: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result)
}
}

var commentTestToml = []byte(`
# postgres it's a comment on type
[postgres]
noComment = "cvalue"
# A comment on AttrB
password = "bvalue"
# A comment on AttrA
user = "avalue"
# a comment on My
[[postgres.My]]
# a comment on My
[[postgres.My]]
`)

func TestMarshalComment(t *testing.T) {
type TypeC struct {
my string
}
type TypeB struct {
AttrA string `toml:"user" comment:"A comment on AttrA"`
AttrB string `toml:"password" comment:"A comment on AttrB"`
AttrC string `toml:"noComment"`
My []TypeC `comment:"a comment on My"`
}
type TypeA struct {
TypeB TypeB `toml:"postgres" comment:"it's a comment on type"`
}

ta := []TypeC{{my: "Foo"}, {my: "Baar"}}
config := TypeA{TypeB{AttrA: "avalue", AttrB: "bvalue", AttrC: "cvalue", My: ta}}
result, err := Marshal(config)
if err != nil {
t.Fatal(err)
}
expected := commentTestToml
if !bytes.Equal(result, expected) {
t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result)
}
}
6 changes: 3 additions & 3 deletions parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ func (p *tomlParser) parseGroupArray() tomlParserStateFn {
newTree := newTree()
newTree.position = startToken.Position
array = append(array, newTree)
p.tree.SetPath(p.currentTable, array)
p.tree.SetPath(p.currentTable, nil, array)

// remove all keys that were children of this table array
prefix := key.val + "."
Expand Down Expand Up @@ -205,7 +205,7 @@ func (p *tomlParser) parseAssign() tomlParserStateFn {
case *Tree, []*Tree:
toInsert = value
default:
toInsert = &tomlValue{value, key.Position}
toInsert = &tomlValue{value: value, position: key.Position}
}
targetNode.values[keyVal] = toInsert
return p.parseStart
Expand Down Expand Up @@ -299,7 +299,7 @@ Loop:
key := p.getToken()
p.assume(tokenEqual)
value := p.parseRvalue()
tree.Set(key.val, value)
tree.Set(key.val, nil, value)
case tokenComma:
if previous == nil {
p.raiseError(follow, "inline table cannot start with a comma")
Expand Down
2 changes: 1 addition & 1 deletion parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func assertTree(t *testing.T, tree *Tree, err error, ref map[string]interface{})
func TestCreateSubTree(t *testing.T) {
tree := newTree()
tree.createSubTree([]string{"a", "b", "c"}, Position{})
tree.Set("a.b.c", 42)
tree.Set("a.b.c", nil, 42)
if tree.Get("a.b.c") != 42 {
t.Fail()
}
Expand Down
12 changes: 8 additions & 4 deletions toml.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@ import (

type tomlValue struct {
value interface{} // string, int64, uint64, float64, bool, time.Time, [] of any of this list
comment *string
position Position
}

// Tree is the result of the parsing of a TOML file.
type Tree struct {
values map[string]interface{} // string -> *tomlValue, *Tree, []*Tree
comment *string
position Position
}

Expand Down Expand Up @@ -177,14 +179,14 @@ func (t *Tree) GetDefault(key string, def interface{}) interface{} {
// Set an element in the tree.
// Key is a dot-separated path (e.g. a.b.c).
// Creates all necessary intermediate trees, if needed.
func (t *Tree) Set(key string, value interface{}) {
t.SetPath(strings.Split(key, "."), value)
func (t *Tree) Set(key string, comment *string, value interface{}) {
t.SetPath(strings.Split(key, "."), comment, value)
}

// SetPath sets an element in the tree.
// Keys is an array of path elements (e.g. {"a","b","c"}).
// Creates all necessary intermediate trees, if needed.
func (t *Tree) SetPath(keys []string, value interface{}) {
func (t *Tree) SetPath(keys []string, comment *string, value interface{}) {
subtree := t
for _, intermediateKey := range keys[:len(keys)-1] {
nextTree, exists := subtree.values[intermediateKey]
Expand All @@ -210,12 +212,14 @@ func (t *Tree) SetPath(keys []string, value interface{}) {
switch value.(type) {
case *Tree:
toInsert = value
subtree.comment = comment
case []*Tree:
toInsert = value
subtree.comment = comment
case *tomlValue:
toInsert = value
default:
toInsert = &tomlValue{value: value}
toInsert = &tomlValue{value: value, comment: comment}
}

subtree.values[keys[len(keys)-1]] = toInsert
Expand Down
6 changes: 3 additions & 3 deletions tomltree_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ func sliceToTree(object interface{}) (interface{}, error) {
}
arrayValue = reflect.Append(arrayValue, reflect.ValueOf(simpleValue))
}
return &tomlValue{arrayValue.Interface(), Position{}}, nil
return &tomlValue{value: arrayValue.Interface(), position: Position{}}, nil
}

func toTree(object interface{}) (interface{}, error) {
Expand All @@ -127,7 +127,7 @@ func toTree(object interface{}) (interface{}, error) {
}
values[key.String()] = newValue
}
return &Tree{values, Position{}}, nil
return &Tree{values: values, position: Position{}}, nil
}

if value.Kind() == reflect.Array || value.Kind() == reflect.Slice {
Expand All @@ -138,5 +138,5 @@ func toTree(object interface{}) (interface{}, error) {
if err != nil {
return nil, err
}
return &tomlValue{simpleValue, Position{}}, nil
return &tomlValue{value: simpleValue, position: Position{}}, nil
}
23 changes: 22 additions & 1 deletion tomltree_write.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,14 @@ func (t *Tree) writeTo(w io.Writer, indent, keyspace string, bytesCount int64) (
return bytesCount, err
}

if v.comment != nil {
writtenBytesCountComment, errc := writeStrings(w, "\n", indent, "# ", *v.comment, "\n")
bytesCount += int64(writtenBytesCountComment)
if errc != nil {
return bytesCount, errc
}
}

writtenBytesCount, err := writeStrings(w, indent, k, " = ", repr, "\n")
bytesCount += int64(writtenBytesCount)
if err != nil {
Expand All @@ -132,10 +140,16 @@ func (t *Tree) writeTo(w io.Writer, indent, keyspace string, bytesCount int64) (
if keyspace != "" {
combinedKey = keyspace + "." + combinedKey
}

switch node := v.(type) {
// node has to be of those two types given how keys are sorted above
case *Tree:
if t.comment != nil {
writtenBytesCountComment, errc := writeStrings(w, "\n", indent, "# ", combinedKey, " ", *t.comment)
bytesCount += int64(writtenBytesCountComment)
if errc != nil {
return bytesCount, errc
}
}
writtenBytesCount, err := writeStrings(w, "\n", indent, "[", combinedKey, "]\n")
bytesCount += int64(writtenBytesCount)
if err != nil {
Expand All @@ -147,6 +161,13 @@ func (t *Tree) writeTo(w io.Writer, indent, keyspace string, bytesCount int64) (
}
case []*Tree:
for _, subTree := range node {
if t.comment != nil {
writtenBytesCountComment, errc := writeStrings(w, "\n", indent, "# ", *t.comment)
bytesCount += int64(writtenBytesCountComment)
if errc != nil {
return bytesCount, errc
}
}
writtenBytesCount, err := writeStrings(w, "\n", indent, "[[", combinedKey, "]]\n")
bytesCount += int64(writtenBytesCount)
if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions tomltree_write_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,13 +161,13 @@ func TestTreeWriteToInvalidTreeSimpleValue(t *testing.T) {
}

func TestTreeWriteToInvalidTreeTomlValue(t *testing.T) {
tree := Tree{values: map[string]interface{}{"foo": &tomlValue{int8(1), Position{}}}}
tree := Tree{values: map[string]interface{}{"foo": &tomlValue{value: int8(1), comment: nil, position: Position{}}}}
_, err := tree.ToTomlString()
assertErrorString(t, "unsupported value type int8: 1", err)
}

func TestTreeWriteToInvalidTreeTomlValueArray(t *testing.T) {
tree := Tree{values: map[string]interface{}{"foo": &tomlValue{[]interface{}{int8(1)}, Position{}}}}
tree := Tree{values: map[string]interface{}{"foo": &tomlValue{value: int8(1), comment: nil, position: Position{}}}}
_, err := tree.ToTomlString()
assertErrorString(t, "unsupported value type int8: 1", err)
}
Expand Down

0 comments on commit c58d639

Please sign in to comment.