Support literal multiline marshal (#485)

Use struct tag `multiline:"true" literal:"true"` to enable it.
This commit is contained in:
Thomas Pelletier
2021-03-25 20:57:38 -04:00
committed by GitHub
parent b59c12a70d
commit ce6fbd7bc0
4 changed files with 46 additions and 1 deletions
+7
View File
@@ -18,6 +18,7 @@ const (
tagFieldComment = "comment" tagFieldComment = "comment"
tagCommented = "commented" tagCommented = "commented"
tagMultiline = "multiline" tagMultiline = "multiline"
tagLiteral = "literal"
tagDefault = "default" tagDefault = "default"
) )
@@ -27,6 +28,7 @@ type tomlOpts struct {
comment string comment string
commented bool commented bool
multiline bool multiline bool
literal bool
include bool include bool
omitempty bool omitempty bool
defaultValue string defaultValue string
@@ -46,6 +48,7 @@ type annotation struct {
comment string comment string
commented string commented string
multiline string multiline string
literal string
defaultValue string defaultValue string
} }
@@ -54,6 +57,7 @@ var annotationDefault = annotation{
comment: tagFieldComment, comment: tagFieldComment,
commented: tagCommented, commented: tagCommented,
multiline: tagMultiline, multiline: tagMultiline,
literal: tagLiteral,
defaultValue: tagDefault, defaultValue: tagDefault,
} }
@@ -442,6 +446,7 @@ func (e *Encoder) valueToTree(mtype reflect.Type, mval reflect.Value) (*Tree, er
Comment: opts.comment, Comment: opts.comment,
Commented: opts.commented, Commented: opts.commented,
Multiline: opts.multiline, Multiline: opts.multiline,
Literal: opts.literal,
}, val) }, val)
} }
} }
@@ -1168,6 +1173,7 @@ func tomlOptions(vf reflect.StructField, an annotation) tomlOpts {
} }
commented, _ := strconv.ParseBool(vf.Tag.Get(an.commented)) commented, _ := strconv.ParseBool(vf.Tag.Get(an.commented))
multiline, _ := strconv.ParseBool(vf.Tag.Get(an.multiline)) multiline, _ := strconv.ParseBool(vf.Tag.Get(an.multiline))
literal, _ := strconv.ParseBool(vf.Tag.Get(an.literal))
defaultValue := vf.Tag.Get(tagDefault) defaultValue := vf.Tag.Get(tagDefault)
result := tomlOpts{ result := tomlOpts{
name: vf.Name, name: vf.Name,
@@ -1175,6 +1181,7 @@ func tomlOptions(vf reflect.StructField, an annotation) tomlOpts {
comment: comment, comment: comment,
commented: commented, commented: commented,
multiline: multiline, multiline: multiline,
literal: literal,
include: true, include: true,
omitempty: false, omitempty: false,
defaultValue: defaultValue, defaultValue: defaultValue,
+26
View File
@@ -1294,6 +1294,32 @@ NonCommented = "Not commented line"
} }
} }
func TestMarshalMultilineLiteral(t *testing.T) {
type Doc struct {
Value string `multiline:"true" literal:"true"`
}
d := Doc{
Value: "hello\nworld\ttest\nend",
}
expected := []byte(`Value = '''
hello
world test
end
'''
`)
b, err := Marshal(d)
if err != nil {
t.Fatal("unexpected error")
}
if !bytes.Equal(b, expected) {
t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, b)
}
}
func TestMarshalNonPrimitiveTypeCommented(t *testing.T) { func TestMarshalNonPrimitiveTypeCommented(t *testing.T) {
expectedToml := []byte(` expectedToml := []byte(`
# [CommentedMapField] # [CommentedMapField]
+4
View File
@@ -15,6 +15,7 @@ type tomlValue struct {
comment string comment string
commented bool commented bool
multiline bool multiline bool
literal bool
position Position position Position
} }
@@ -314,6 +315,7 @@ type SetOptions struct {
Comment string Comment string
Commented bool Commented bool
Multiline bool Multiline bool
Literal bool
} }
// SetWithOptions is the same as Set, but allows you to provide formatting // SetWithOptions is the same as Set, but allows you to provide formatting
@@ -362,12 +364,14 @@ func (t *Tree) SetPathWithOptions(keys []string, opts SetOptions, value interfac
v.comment = opts.Comment v.comment = opts.Comment
v.commented = opts.Commented v.commented = opts.Commented
v.multiline = opts.Multiline v.multiline = opts.Multiline
v.literal = opts.Literal
toInsert = v toInsert = v
default: default:
toInsert = &tomlValue{value: value, toInsert = &tomlValue{value: value,
comment: opts.Comment, comment: opts.Comment,
commented: opts.Commented, commented: opts.Commented,
multiline: opts.Multiline, multiline: opts.Multiline,
literal: opts.Literal,
position: Position{Line: subtree.position.Line + len(subtree.values) + 1, Col: subtree.position.Col}} position: Position{Line: subtree.position.Line + len(subtree.values) + 1, Col: subtree.position.Col}}
} }
+9 -1
View File
@@ -158,7 +158,15 @@ func tomlValueStringRepresentation(v interface{}, commented string, indent strin
return strings.ToLower(strconv.FormatFloat(value, 'f', -1, bits)), nil return strings.ToLower(strconv.FormatFloat(value, 'f', -1, bits)), nil
case string: case string:
if tv.multiline { if tv.multiline {
return "\"\"\"\n" + encodeMultilineTomlString(value, commented) + "\"\"\"", nil if tv.literal {
b := strings.Builder{}
b.WriteString("'''\n")
b.Write([]byte(value))
b.WriteString("\n'''")
return b.String(), nil
} else {
return "\"\"\"\n" + encodeMultilineTomlString(value, commented) + "\"\"\"", nil
}
} }
return "\"" + encodeTomlString(value) + "\"", nil return "\"" + encodeTomlString(value) + "\"", nil
case []byte: case []byte: