...

Source file src/github.com/peterbourgon/ff/v3/json.go

Documentation: github.com/peterbourgon/ff/v3

     1  package ff
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"io"
     7  	"strconv"
     8  )
     9  
    10  // JSONParser is a parser for config files in JSON format. Input should be
    11  // an object. The object's keys are treated as flag names, and the object's
    12  // values as flag values. If the value is an array, the flag will be set
    13  // multiple times.
    14  func JSONParser(r io.Reader, set func(name, value string) error) error {
    15  	var m map[string]interface{}
    16  	d := json.NewDecoder(r)
    17  	d.UseNumber() // must set UseNumber for stringifyValue to work
    18  	if err := d.Decode(&m); err != nil {
    19  		return JSONParseError{Inner: err}
    20  	}
    21  	for key, val := range m {
    22  		values, err := stringifySlice(val)
    23  		if err != nil {
    24  			return JSONParseError{Inner: err}
    25  		}
    26  		for _, value := range values {
    27  			if err := set(key, value); err != nil {
    28  				return err
    29  			}
    30  		}
    31  	}
    32  	return nil
    33  }
    34  
    35  func stringifySlice(val interface{}) ([]string, error) {
    36  	if vals, ok := val.([]interface{}); ok {
    37  		ss := make([]string, len(vals))
    38  		for i := range vals {
    39  			s, err := stringifyValue(vals[i])
    40  			if err != nil {
    41  				return nil, err
    42  			}
    43  			ss[i] = s
    44  		}
    45  		return ss, nil
    46  	}
    47  	s, err := stringifyValue(val)
    48  	if err != nil {
    49  		return nil, err
    50  	}
    51  	return []string{s}, nil
    52  }
    53  
    54  func stringifyValue(val interface{}) (string, error) {
    55  	switch v := val.(type) {
    56  	case string:
    57  		return v, nil
    58  	case json.Number:
    59  		return v.String(), nil
    60  	case bool:
    61  		return strconv.FormatBool(v), nil
    62  	default:
    63  		return "", StringConversionError{Value: val}
    64  	}
    65  }
    66  
    67  // JSONParseError wraps all errors originating from the JSONParser.
    68  type JSONParseError struct {
    69  	Inner error
    70  }
    71  
    72  // Error implenents the error interface.
    73  func (e JSONParseError) Error() string {
    74  	return fmt.Sprintf("error parsing JSON config: %v", e.Inner)
    75  }
    76  
    77  // Unwrap implements the errors.Wrapper interface, allowing errors.Is and
    78  // errors.As to work with JSONParseErrors.
    79  func (e JSONParseError) Unwrap() error {
    80  	return e.Inner
    81  }
    82  
    83  // StringConversionError is returned when a value in a config file
    84  // can't be converted to a string, to be provided to a flag.
    85  type StringConversionError struct {
    86  	Value interface{}
    87  }
    88  
    89  // Error implements the error interface.
    90  func (e StringConversionError) Error() string {
    91  	return fmt.Sprintf("couldn't convert %q (type %T) to string", e.Value, e.Value)
    92  }
    93  

View as plain text