Add Flow option for Encoder

This commit is contained in:
Masaaki Goshima 2019-10-31 13:29:43 +09:00
parent 5e642017ee
commit e4be76e5f8
3 changed files with 49 additions and 9 deletions

View file

@ -28,6 +28,7 @@ type Encoder struct {
writer io.Writer writer io.Writer
opts []EncodeOption opts []EncodeOption
indent int indent int
isFlowStyle bool
anchorPtrToNameMap map[uintptr]string anchorPtrToNameMap map[uintptr]string
line int line int
@ -64,6 +65,11 @@ func (e *Encoder) Close() error {
// //
// See the documentation for Marshal for details about the conversion of Go values to YAML. // See the documentation for Marshal for details about the conversion of Go values to YAML.
func (e *Encoder) Encode(v interface{}) error { func (e *Encoder) Encode(v interface{}) error {
for _, opt := range e.opts {
if err := opt(e); err != nil {
return errors.Wrapf(err, "failed to run option for encoder")
}
}
node, err := e.encodeValue(reflect.ValueOf(v), 1) node, err := e.encodeValue(reflect.ValueOf(v), 1)
if err != nil { if err != nil {
return errors.Wrapf(err, "failed to encode value") return errors.Wrapf(err, "failed to encode value")
@ -225,10 +231,7 @@ func (e *Encoder) encodeBool(v bool) ast.Node {
} }
func (e *Encoder) encodeSlice(value reflect.Value) (ast.Node, error) { func (e *Encoder) encodeSlice(value reflect.Value) (ast.Node, error) {
sequence := &ast.SequenceNode{ sequence := ast.Sequence(token.New("-", "-", e.pos(e.column)), e.isFlowStyle)
Start: token.New("-", "-", e.pos(e.column)),
Values: []ast.Node{},
}
for i := 0; i < value.Len(); i++ { for i := 0; i < value.Len(); i++ {
node, err := e.encodeValue(value.Index(i), e.column) node, err := e.encodeValue(value.Index(i), e.column)
if err != nil { if err != nil {
@ -259,7 +262,7 @@ func (e *Encoder) encodeMapItem(item MapItem, column int) (*ast.MappingValueNode
} }
func (e *Encoder) encodeMapSlice(value MapSlice, column int) (ast.Node, error) { func (e *Encoder) encodeMapSlice(value MapSlice, column int) (ast.Node, error) {
node := ast.Mapping(token.New("", "", e.pos(column)), false) node := ast.Mapping(token.New("", "", e.pos(column)), e.isFlowStyle)
for _, item := range value { for _, item := range value {
value, err := e.encodeMapItem(item, column) value, err := e.encodeMapItem(item, column)
if err != nil { if err != nil {
@ -271,7 +274,7 @@ func (e *Encoder) encodeMapSlice(value MapSlice, column int) (ast.Node, error) {
} }
func (e *Encoder) encodeMap(value reflect.Value, column int) ast.Node { func (e *Encoder) encodeMap(value reflect.Value, column int) ast.Node {
node := ast.Mapping(token.New("", "", e.pos(column)), false) node := ast.Mapping(token.New("", "", e.pos(column)), e.isFlowStyle)
keys := []string{} keys := []string{}
for _, k := range value.MapKeys() { for _, k := range value.MapKeys() {
keys = append(keys, k.Interface().(string)) keys = append(keys, k.Interface().(string))
@ -345,7 +348,7 @@ func (e *Encoder) isZeroValue(v reflect.Value) bool {
} }
func (e *Encoder) encodeStruct(value reflect.Value, column int) (ast.Node, error) { func (e *Encoder) encodeStruct(value reflect.Value, column int) (ast.Node, error) {
node := ast.Mapping(token.New("", "", e.pos(column)), false) node := ast.Mapping(token.New("", "", e.pos(column)), e.isFlowStyle)
structType := value.Type() structType := value.Type()
structFieldMap, err := structFieldMap(structType) structFieldMap, err := structFieldMap(structType)
if err != nil { if err != nil {
@ -367,7 +370,7 @@ func (e *Encoder) encodeStruct(value reflect.Value, column int) (ast.Node, error
return nil, errors.Wrapf(err, "failed to encode value") return nil, errors.Wrapf(err, "failed to encode value")
} }
if m, ok := value.(*ast.MappingNode); ok { if m, ok := value.(*ast.MappingNode); ok {
if structField.IsFlow { if !e.isFlowStyle && structField.IsFlow {
m.IsFlowStyle = true m.IsFlowStyle = true
} }
for _, value := range m.Values { for _, value := range m.Values {
@ -375,7 +378,7 @@ func (e *Encoder) encodeStruct(value reflect.Value, column int) (ast.Node, error
value.Value.GetToken().Position.Column += e.indent value.Value.GetToken().Position.Column += e.indent
} }
} else if s, ok := value.(*ast.SequenceNode); ok { } else if s, ok := value.(*ast.SequenceNode); ok {
if structField.IsFlow { if !e.isFlowStyle && structField.IsFlow {
s.IsFlowStyle = true s.IsFlowStyle = true
} }
} }

View file

@ -495,6 +495,35 @@ c: true
} }
} }
func TestEncoder_Flow(t *testing.T) {
var buf bytes.Buffer
enc := yaml.NewEncoder(&buf, yaml.Flow(true))
var v struct {
A int
B string
C struct {
D int
E string
}
F []int
}
v.A = 1
v.B = "hello"
v.C.D = 3
v.C.E = "world"
v.F = []int{1, 2}
if err := enc.Encode(v); err != nil {
t.Fatalf("%+v", err)
}
expect := `
{a: 1, b: hello, c: {d: 3, e: world}, f: [1, 2]}
`
actual := "\n" + buf.String()
if expect != actual {
t.Fatalf("flow style marshal error: expect=[%s] actual=[%s]", expect, actual)
}
}
func Example_Marshal_ExplicitAnchorAlias() { func Example_Marshal_ExplicitAnchorAlias() {
type T struct { type T struct {
A int A int

View file

@ -55,3 +55,11 @@ func Indent(spaces int) EncodeOption {
return nil return nil
} }
} }
// Flow encoding by flow style
func Flow(isFlowStyle bool) EncodeOption {
return func(e *Encoder) error {
e.isFlowStyle = isFlowStyle
return nil
}
}