func ExampleGetFieldKind() { s := MyStruct{ FirstField: "first value", SecondField: 2, ThirdField: "third value", } var firstFieldKind reflect.Kind var secondFieldKind reflect.Kind var err error // GetFieldKind will return reflect.String firstFieldKind, err = reflections.GetFieldKind(s, "FirstField") if err != nil { log.Fatal(err) } fmt.Println(firstFieldKind) // GetFieldKind will return reflect.Int secondFieldKind, err = reflections.GetFieldKind(s, "SecondField") if err != nil { log.Fatal(err) } fmt.Println(secondFieldKind) }
func (r *Row) Bind(x interface{}, strategy map[string]string) error { for src, dest := range strategy { data, ok := r.data[src] if ok { k, err := reflections.GetFieldKind(x, dest) if err != nil { return err } switch k { case reflect.String: { reflections.SetField(x, dest, data) } case reflect.Int64: { i, err := strconv.ParseInt(data, 10, 64) if err != nil { return err } reflections.SetField(x, dest, i) } case reflect.Ptr: { value, err := reflections.GetField(x, dest) if err != nil { return err } if reflect.TypeOf(value) == typeDec { dec, success := new(inf.Dec).SetString(data) if !success { fmt.Errorf("Could not parse inf.Dec: %s", data) } reflections.SetField(x, dest, dec) } } case reflect.Struct: { value, err := reflections.GetField(x, dest) if err != nil { return err } if reflect.TypeOf(value) == typeTime { date, err := time.ParseInLocation("2006-01-02 15:04:05", data, r.opts.TimeZone) if err != nil { return err } reflections.SetField(x, dest, date) } } } } } return nil }
func validFieldType(fieldName string, target interface{}, fieldType string) bool { fieldKind, err := reflections.GetFieldKind(target, fieldName) if err != nil { return false } return fieldKind == fieldKindFromFieldType(fieldType) }
func (l Loader) fieldValueIsEmpty(fieldName string) bool { // We need to use the field kind to determine the type of empty test. value, _ := reflections.GetField(l.Config, fieldName) fieldKind, _ := reflections.GetFieldKind(l.Config, fieldName) if fieldKind == reflect.String { return value == "" } else if fieldKind == reflect.Slice { v := reflect.ValueOf(value) return v.Len() == 0 } else if fieldKind == reflect.Bool { return value == false } else { panic(fmt.Sprintf("Can't determine empty-ness for field type %s", fieldKind)) } return false }
// createFieldInfos creates the fieldInfos for a struct s. // Only information from the struct (headerName, fieldName and kind) is available, // all field positions are initialized with an invalid value of -1 func createFieldInfos(s interface{}) (fieldInfos, error) { if reflect.TypeOf(s).Kind() != reflect.Struct { return nil, ErrNoStruct } fieldInfos := []fieldInfo{} headerNameMap := map[string]interface{}{} // to detect duplicate csv tag names fieldNames, err := reflections.Fields(s) if err != nil { return nil, err } for _, fieldName := range fieldNames { headerName, err := reflections.GetFieldTag(s, fieldName, "csv") if err != nil { return nil, err } // csv fieldtags that contain a dash are ignored if strings.Contains(headerName, "-") { continue } if _, ok := headerNameMap[headerName]; ok { return nil, fmt.Errorf("duplicate csv tag name: %s", headerName) } headerNameMap[headerName] = nil kind, err := reflections.GetFieldKind(s, fieldName) if err != nil { return nil, err } if len(headerName) == 0 { return nil, fmt.Errorf("empty csv tag for field: %s", fieldName) } fieldInfos = append(fieldInfos, fieldInfo{ headerName: headerName, fieldName: fieldName, position: -1, kind: kind, }) } return fieldInfos, nil }
// SetField sets the value of the given field. func (dc *DeepCopier) SetField(options *FieldOptions) error { if options.Skip { return nil } if dc.Reversed { has, _ := reflections.HasField(dc.Destination, options.SourceField) if !has { return nil } } has, _ := reflections.HasField(dc.Source, options.SourceField) if !has { err := dc.HandleMethod(options) if err != nil { has, _ = reflections.HasField(dc.Destination, options.DestinationField) if has { return nil } } return nil } kind, _ := reflections.GetFieldKind(dc.Source, options.SourceField) if kind == reflect.Struct { if err := dc.HandleStructField(options); err != nil { return err } return nil } if err := dc.HandleField(options); err != nil { return err } return nil }
func (l Loader) normalizeField(fieldName string, normalization string) error { if normalization == "filepath" { value, _ := reflections.GetField(l.Config, fieldName) fieldKind, _ := reflections.GetFieldKind(l.Config, fieldName) // Make sure we're normalizing a string filed if fieldKind != reflect.String { return fmt.Errorf("filepath normalization only works on string fields") } // Normalize the field to be a filepath if valueAsString, ok := value.(string); ok { normalizedPath := NormalizeFilePath(valueAsString) if err := reflections.SetField(l.Config, fieldName, normalizedPath); err != nil { return err } } } else { return fmt.Errorf("Unknown normalization `%s`", normalization) } return nil }
func formTagFromField(fieldName string, target interface{}) (string, error) { fieldKind, err := reflections.GetFieldKind(target, fieldName) f, _ := reflections.GetField(target, fieldName) fmt.Printf("Field %v\n", f) if err != nil { return "", err } choices, _ := reflections.GetFieldTag(target, fieldName, "choices") switch fieldKind { case reflect.String: if choices != "" { return "list", nil } return "input", nil case reflect.Slice: return "checkbox", nil case reflect.Bool: return "confirm", nil } return "", nil }
// Reflects on the values in the commandLineOptions structure, and fills it // with values either from the command line, or from the ENV. func parseArgs(opts *commandLineOptions, args []string) { // Create a flag set for args flags := flag.NewFlagSet(commandLineName, flag.ExitOnError) // Get the fields for the strucutre fields, _ := reflections.Fields(opts) // Loop through each field of the structure, and define a flag for it for i := 0; i < len(fields); i++ { fieldName := fields[i] flagName, _ := reflections.GetFieldTag(opts, fieldName, "flag") fieldKind, _ := reflections.GetFieldKind(opts, fieldName) if fieldKind == reflect.String { flags.String(flagName, "", "") } else if fieldKind == reflect.Bool { flags.Bool(flagName, false, "") } else { exitAndError(fmt.Sprintf("Could not create flag for %s", fieldName)) } } // Define our custom usage text flags.Usage = func() { fmt.Printf("%s\n", commandLineUsage) } // Search the args until we find a "--", which signifies the user has started // defining options. var argumentFlags []string started := false for i := 0; i < len(args); i++ { if strings.HasPrefix(args[i], "--") { started = true } if started { argumentFlags = append(argumentFlags, args[i]) } } // Now parse the flags flags.Parse(argumentFlags) // Now the flag set has been populated with values, retrieve them and // set them (or use the ENV variable if empty) for i := 0; i < len(fields); i++ { fieldName := fields[i] fieldKind, _ := reflections.GetFieldKind(opts, fieldName) // Grab the flags we need flagName, _ := reflections.GetFieldTag(opts, fieldName, "flag") envName, _ := reflections.GetFieldTag(opts, fieldName, "env") required, _ := reflections.GetFieldTag(opts, fieldName, "required") // Grab the value from the flag value := flags.Lookup(flagName).Value.String() // If the value of the flag is empty, try the ENV if value == "" { value = os.Getenv(envName) } // Do validation if required == "true" && value == "" { exitAndError(fmt.Sprintf("missing %s", flagName)) } // Set the value in the right way if fieldKind == reflect.String { reflections.SetField(opts, fieldName, value) } else if fieldKind == reflect.Bool { // The bool is converted to a string above if value == "true" { reflections.SetField(opts, fieldName, true) } else { reflections.SetField(opts, fieldName, false) } } else { exitAndError(fmt.Sprintf("Could not set value of %s", fieldName)) } } }
func (l Loader) setFieldValueFromCLI(fieldName string, cliName string) error { // Get the kind of field we need to set fieldKind, err := reflections.GetFieldKind(l.Config, fieldName) if err != nil { return fmt.Errorf(`Failed to get the type of struct field %s`, fieldName) } var value interface{} // See the if the cli option is using the special format i.e. (arg:1) special := CLISpecialNameRegex.FindStringSubmatch(cliName) if len(special) == 3 { // Should this cli option be loaded from the CLI arguments? if special[1] == "arg" { // Convert the arg position to an integer i, err := strconv.Atoi(special[2]) if err != nil { return fmt.Errorf("Failed to convert string to int: %s", err) } // Only set the value if the args are long enough for // the position to exist. if len(l.CLI.Args()) > i { // Get the value from the args value = l.CLI.Args()[i] } } } else { // If the cli name didn't have the special format, then we need to // either load from the context's flags, or from a config file. // We start by defaulting the value to what ever was provided // by the configuration file if l.File != nil { if configFileValue, ok := l.File.Config[cliName]; ok { // Convert the config file value to it's correct type if fieldKind == reflect.String { value = configFileValue } else if fieldKind == reflect.Slice { value = strings.Split(configFileValue, ",") } else if fieldKind == reflect.Bool { value, _ = strconv.ParseBool(configFileValue) } else { return fmt.Errorf("Unable to convert string to type %s", fieldKind) } } } // If a value hasn't been found in a config file, but there // _is_ one provided by the CLI context, then use that. if value == nil || l.cliValueIsSet(cliName) { if fieldKind == reflect.String { value = l.CLI.String(cliName) } else if fieldKind == reflect.Slice { value = l.CLI.StringSlice(cliName) } else if fieldKind == reflect.Bool { value = l.CLI.Bool(cliName) } else { return fmt.Errorf("Unable to handle type: %s", fieldKind) } } } // Set the value to the cfg if value != nil { err = reflections.SetField(l.Config, fieldName, value) if err != nil { return fmt.Errorf("Could not set value `%s` to field `%s` (%s)", value, fieldName, err) } } return nil }