Documentation
¶
Overview ¶
Package mapdecode implements a generic interface{} decoder. It allows implementing custom YAML/JSON decoding logic only once. Instead of implementing the same UnmarshalYAML and UnmarshalJSON twice, you can implement Decode once, parse the YAML/JSON input into a map[string]interface{} and decode it using this package.
var data map[string]interface{} if err := json.Decode(&data, input); err != nil { log.Fatal(err) } var result MyStruct if err := mapdecode.Decode(&result, data); err != nil { log.Fatal(err) }
This also makes it possible to implement custom markup parsing and deserialization strategies that get decoded into a user-provided struct.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Decode ¶
Decode from src into dest where dest is a pointer to the value being decoded.
Primitives are mapped as-is with pointers created or dereferenced as necessary. Maps and slices use Decode recursively for each of their items. For structs, the source must be a map[string]interface{} or map[interface{}]interface{}. Each key in the map calls Decode recursively with the field of the struct that has a name similar to the key (case insensitive match).
var item struct{ Key, Value string } err := Decode(&item, map[string]string{"key": "some key", "Value": "some value"})
The name of the field in the map may be customized with the `mapdecode` tag. (Use the TagName option to change the name of the tag.)
var item struct { Key string `mapdecode:"name"` Value string } var item struct{ Key, Value string } err := Decode(&item, map[string]string{"name": "token", "Value": "some value"})
The destination type or any subtype may implement the Decoder interface to customize how it gets decoded.
Example ¶
type Item struct { Key string `mapdecode:"name"` Value string } var item Item err := Decode(&item, map[string]interface{}{ "name": "foo", "value": "bar", }) if err != nil { panic(err) } fmt.Println(item.Key, item.Value)
Output: foo bar
Example (Decoder) ¶
var ss StringSet err := Decode(&ss, []interface{}{"foo", "bar", "foo", "baz"}) if err != nil { panic(err) } var items []string for item := range ss { items = append(items, item) } sort.Strings(items) fmt.Println(items)
Output: [bar baz foo]
Types ¶
type DecodeHookFunc ¶
DecodeHookFunc is a hook called before decoding a value into a specific type.
type Decoder ¶
type Decoder interface { // Decode receives a function that will attempt to decode the source data // into the given target. The argument to Into MUST be a pointer to the // target object. Decode(Into) error }
Decoder is any type which has custom decoding logic. Types may implement Decode and rely on the given Into function to read values into a different shape, validate the result, and fill themselves with it.
For example the following lets users provide a list of strings to decode a set.
type StringSet map[string]struct{} func (ss *StringSet) Decode(into mapdecode.Into) error { var items []string if err := into(&items); err != nil { return err } *ss = make(map[string]struct{}) for _, item := range items { (*ss)[item] = struct{}{} } return nil }
type FieldHookFunc ¶
type FieldHookFunc func(from reflect.Type, to reflect.StructField, data reflect.Value) (reflect.Value, error)
FieldHookFunc is a hook called while decoding a specific struct field. It receives the source type, information about the target field, and the source data.
type Into ¶
type Into func(dest interface{}) error
Into is a function that attempts to decode the source data into the given shape.
Types that implement Decoder are provided a reference to an Into object so that they can decode a different shape, validate the result and populate themselves with the result.
var values []string err := into(&value) for _, value := range values { if value == "reserved" { return errors.New(`a value in the list cannot be "reserved"`) } self.Values = append(self.Values, value) }
The function is safe to call multiple times if you need to try to decode different shapes. For example,
// Allow the user to just use the string "default" for the default // configuration. var name string if err := into(&name); err == nil { if name == "default" { *self = DefaultConfiguration return } return fmt.Errorf("unknown name %q", name) } // Otherwise, the user must provide {someAttr: "value"} as the input for // explicit configuration. var custom struct{ SomeAttr string } if err := into(&custom); err != nil { return err } self.SomeAttr = custom return nil
If the destination type or any sub-type implements Decoder, that function will be called. This means that Into MUST NOT be called on the type whose Decode function is currently running or this will end up in an infinite loop.
type Option ¶
type Option func(*options)
Option customizes the behavior of Decode.
func DecodeHook ¶
func DecodeHook(f DecodeHookFunc) Option
DecodeHook registers a hook to be called before a value is decoded by the system.
This hook will be called with information about the target type and the source data that will fill it.
Multiple decode hooks may be specified by providing this option multiple times. Hooks are exected in-order, feeding values from one hook to the next.
func FieldHook ¶
func FieldHook(f FieldHookFunc) Option
FieldHook registers a hook to be called when a struct field is being decoded by the system.
This hook will be called with information about the target field of a struct and the source data that will fill it.
Field hooks may return a value of the same type as the source data or the same type as the target. Other value decoding hooks will still be executed on this field.
Multiple field hooks may be specified by providing this option multiple times. Hooks are exected in-order, feeding values from one hook to the next.
func IgnoreUnused ¶
IgnoreUnused specifies whether we should ignore unused attributes in YAML. By default, decoding will fail if an unused attribute is encountered.
func TagName ¶
TagName changes the name of the struct tag under which field names are expected.
Example ¶
var item struct { Value string `foo:"item"` } err := Decode(&item, map[string]interface{}{ "item": "hello", }, TagName("foo")) if err != nil { panic(err) } fmt.Println(item.Value)
Output: hello
func YAML ¶
func YAML() Option
YAML may be specified to decode go-yaml (gopkg.in/yaml.v2) compatible types. Use this option if you have types that implement yaml.Unmarshaler and use the `yaml` tag.
type StringSet map[string]struct{} func (ss *StringSet) UnmarshalYAML(decode func(interface{}) error) error { var items []string if err := decode(&items); err != nil { return err } // .. } var x StringSet mapdecode.Decode(&x, data, mapdecode.YAML())
Caveat: None of the go-yaml flags are supported. Only the attribute name changes will be respected. Further, note that go-yaml ignores unused attributes but mapdecode fails on unused attributes by default. Use IgnoreUnused to cusotmize this behavior.
Directories
¶
Path | Synopsis |
---|---|
Package mapstructure exposes functionality to convert an arbitrary map[string]interface{} into a native Go structure.
|
Package mapstructure exposes functionality to convert an arbitrary map[string]interface{} into a native Go structure. |