mirror of https://github.com/spf13/viper.git
feat(encoding)!: accept a map in the decoder interface
This interface is specific to decoding data into Viper's internal, so it's okay to make it Viper specific. BREAKING CHANGE: the decoder interface now accepts a map instead of an interface Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
This commit is contained in:
parent
6c1745665b
commit
e54e7a53a5
|
@ -4,10 +4,10 @@ import (
|
|||
"sync"
|
||||
)
|
||||
|
||||
// Decoder decodes the contents of b into a v representation.
|
||||
// Decoder decodes the contents of b into v.
|
||||
// It's primarily used for decoding contents of a file into a map[string]interface{}.
|
||||
type Decoder interface {
|
||||
Decode(b []byte, v interface{}) error
|
||||
Decode(b []byte, v map[string]interface{}) error
|
||||
}
|
||||
|
||||
const (
|
||||
|
@ -48,7 +48,7 @@ func (e *DecoderRegistry) RegisterDecoder(format string, enc Decoder) error {
|
|||
}
|
||||
|
||||
// Decode calls the underlying Decoder based on the format.
|
||||
func (e *DecoderRegistry) Decode(format string, b []byte, v interface{}) error {
|
||||
func (e *DecoderRegistry) Decode(format string, b []byte, v map[string]interface{}) error {
|
||||
e.mu.RLock()
|
||||
decoder, ok := e.decoders[format]
|
||||
e.mu.RUnlock()
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
package encoding
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type decoder struct {
|
||||
v interface{}
|
||||
v map[string]interface{}
|
||||
}
|
||||
|
||||
func (d decoder) Decode(_ []byte, v interface{}) error {
|
||||
rv := v.(*string)
|
||||
*rv = d.v.(string)
|
||||
func (d decoder) Decode(_ []byte, v map[string]interface{}) error {
|
||||
for key, value := range d.v {
|
||||
v[key] = value
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -44,7 +46,9 @@ func TestDecoderRegistry_Decode(t *testing.T) {
|
|||
t.Run("OK", func(t *testing.T) {
|
||||
registry := NewDecoderRegistry()
|
||||
decoder := decoder{
|
||||
v: "decoded value",
|
||||
v: map[string]interface{}{
|
||||
"key": "value",
|
||||
},
|
||||
}
|
||||
|
||||
err := registry.RegisterDecoder("myformat", decoder)
|
||||
|
@ -52,24 +56,24 @@ func TestDecoderRegistry_Decode(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var v string
|
||||
v := map[string]interface{}{}
|
||||
|
||||
err = registry.Decode("myformat", []byte("some value"), &v)
|
||||
err = registry.Decode("myformat", []byte("key: value"), v)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if v != "decoded value" {
|
||||
t.Fatalf("expected 'decoded value', got: %#v", v)
|
||||
if !reflect.DeepEqual(decoder.v, v) {
|
||||
t.Fatalf("decoded value does not match the expected one\nactual: %+v\nexpected: %+v", v, decoder.v)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("DecoderNotFound", func(t *testing.T) {
|
||||
registry := NewDecoderRegistry()
|
||||
|
||||
var v string
|
||||
v := map[string]interface{}{}
|
||||
|
||||
err := registry.Decode("myformat", []byte("some value"), &v)
|
||||
err := registry.Decode("myformat", nil, v)
|
||||
if err != ErrDecoderNotFound {
|
||||
t.Fatalf("expected ErrDecoderNotFound, got: %v", err)
|
||||
}
|
||||
|
|
|
@ -35,6 +35,6 @@ func (Codec) Encode(v interface{}) ([]byte, error) {
|
|||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func (Codec) Decode(b []byte, v interface{}) error {
|
||||
return hcl.Unmarshal(b, v)
|
||||
func (Codec) Decode(b []byte, v map[string]interface{}) error {
|
||||
return hcl.Unmarshal(b, &v)
|
||||
}
|
||||
|
|
|
@ -12,6 +12,6 @@ func (Codec) Encode(v interface{}) ([]byte, error) {
|
|||
return json.MarshalIndent(v, "", " ")
|
||||
}
|
||||
|
||||
func (Codec) Decode(b []byte, v interface{}) error {
|
||||
return json.Unmarshal(b, v)
|
||||
func (Codec) Decode(b []byte, v map[string]interface{}) error {
|
||||
return json.Unmarshal(b, &v)
|
||||
}
|
||||
|
|
|
@ -25,21 +25,16 @@ func (Codec) Encode(v interface{}) ([]byte, error) {
|
|||
return toml.Marshal(v)
|
||||
}
|
||||
|
||||
func (Codec) Decode(b []byte, v interface{}) error {
|
||||
func (Codec) Decode(b []byte, v map[string]interface{}) error {
|
||||
tree, err := toml.LoadBytes(b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if m, ok := v.(*map[string]interface{}); ok {
|
||||
vmap := *m
|
||||
tmap := tree.ToMap()
|
||||
for k, v := range tmap {
|
||||
vmap[k] = v
|
||||
}
|
||||
|
||||
return nil
|
||||
tmap := tree.ToMap()
|
||||
for key, value := range tmap {
|
||||
v[key] = value
|
||||
}
|
||||
|
||||
return tree.Unmarshal(v)
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -9,6 +9,6 @@ func (Codec) Encode(v interface{}) ([]byte, error) {
|
|||
return yaml.Marshal(v)
|
||||
}
|
||||
|
||||
func (Codec) Decode(b []byte, v interface{}) error {
|
||||
return yaml.Unmarshal(b, v)
|
||||
func (Codec) Decode(b []byte, v map[string]interface{}) error {
|
||||
return yaml.Unmarshal(b, &v)
|
||||
}
|
||||
|
|
2
viper.go
2
viper.go
|
@ -1635,7 +1635,7 @@ func (v *Viper) unmarshalReader(in io.Reader, c map[string]interface{}) error {
|
|||
|
||||
switch format := strings.ToLower(v.getConfigType()); format {
|
||||
case "yaml", "yml", "json", "toml", "hcl", "tfvars":
|
||||
err := decoderRegistry.Decode(format, buf.Bytes(), &c)
|
||||
err := decoderRegistry.Decode(format, buf.Bytes(), c)
|
||||
if err != nil {
|
||||
return ConfigParseError{err}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue