Skip to content

Commit

Permalink
Make yaml.Node.Decode customizable with decoder options
Browse files Browse the repository at this point in the history
  • Loading branch information
tonickkozlov committed Feb 8, 2024
1 parent f6f7691 commit f3e79e4
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 1 deletion.
29 changes: 29 additions & 0 deletions decode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1703,6 +1703,35 @@ func (s *S) TestUnmarshalKnownFields(c *C) {
}
}

type decoderOptionsTest struct {
Foo int
Bar string
}

// contrived example only for the sake of showcasing the
// custom unmarshalling logic
func (i *decoderOptionsTest) UnmarshalYAML(data *yaml.Node) error {
repr := struct {
Foo int
Bar string
}{}
if err := data.Decode(&repr, yaml.NodeDecoderOptions.KnownFields); err != nil {
return err
}
i.Foo = repr.Foo
i.Bar = repr.Bar
return nil
}

func (s *S) TestDecoderOptions(c *C) {
testData := "foo: 42\nbar: \"bar\"\nsome_random_field: 666"
out := decoderOptionsTest{}
dec := yaml.NewDecoder(bytes.NewBuffer([]byte(testData)))
dec.KnownFields(true)
err := dec.Decode(&out)
c.Assert(err, ErrorMatches, "yaml: unmarshal errors:\n line 3: field some_random_field not found in type struct { Foo int; Bar string }")
}

type textUnmarshaler struct {
S string
}
Expand Down
19 changes: 18 additions & 1 deletion yaml.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,12 +135,29 @@ func (dec *Decoder) Decode(v interface{}) (err error) {
return nil
}

// NodeDecoderOption allows configuring decoder with custom options.
//
// It is especially useful when implementing UnmarshalYAML for custom data types.
type NodeDecoderOption func(d *decoder)

// NodeDecoderOptions stores all currently available decoder configuration options.
var NodeDecoderOptions = struct {
KnownFields NodeDecoderOption
}{
KnownFields: func(d *decoder) {
d.knownFields = true
},
}

// Decode decodes the node and stores its data into the value pointed to by v.
//
// See the documentation for Unmarshal for details about the
// conversion of YAML into a Go value.
func (n *Node) Decode(v interface{}) (err error) {
func (n *Node) Decode(v interface{}, nodeDecoderOptions ...NodeDecoderOption) (err error) {
d := newDecoder()
for _, opt := range nodeDecoderOptions {
opt(d)
}
defer handleErr(&err)
out := reflect.ValueOf(v)
if out.Kind() == reflect.Ptr && !out.IsNil() {
Expand Down

0 comments on commit f3e79e4

Please sign in to comment.