From f3e79e42ed0e65edf388e160c451b5c1d5648e5e Mon Sep 17 00:00:00 2001 From: Anton Kozlov Date: Wed, 7 Feb 2024 12:05:56 +0000 Subject: [PATCH] Make yaml.Node.Decode customizable with decoder options --- decode_test.go | 29 +++++++++++++++++++++++++++++ yaml.go | 19 ++++++++++++++++++- 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/decode_test.go b/decode_test.go index 0364b0bb..c8a722e0 100644 --- a/decode_test.go +++ b/decode_test.go @@ -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 } diff --git a/yaml.go b/yaml.go index 8cec6da4..ee065c5d 100644 --- a/yaml.go +++ b/yaml.go @@ -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() {