func NewParser(config Config, dests ...interface{}) (*Parser, error) {
	p := Parser{
		config: config,
	}
	for _, dest := range dests {
		if dest, ok := dest.(Versioned); ok {
			p.version = dest.Version()
		}
		if dest, ok := dest.(Described); ok {
			p.description = dest.Description()
		}
		v := reflect.ValueOf(dest)
		if v.Kind() != reflect.Ptr {
			panic(fmt.Sprintf("%s is not a pointer (did you forget an ampersand?)", v.Type()))
		}
		v = v.Elem()
		if v.Kind() != reflect.Struct {
			panic(fmt.Sprintf("%T is not a struct pointer", dest))
		}

		var errs []string
		walkFields(v, func(field reflect.StructField, val reflect.Value, t reflect.Type) bool {
			// Check for the ignore switch in the tag
			tag := field.Tag.Get("arg")
			if tag == "-" {
				return false
			}

			// If this is an embedded struct then recurse into its fields
			if field.Anonymous && field.Type.Kind() == reflect.Struct {
				return true
			}

			spec := spec{
				long: strings.ToLower(field.Name),
				dest: val,
			}

			help, exists := field.Tag.Lookup("help")
			if exists {
				spec.help = help
			}

			// Check whether this field is supported. It's good to do this here rather than
			// wait until ParseValue because it means that a program with invalid argument
			// fields will always fail regardless of whether the arguments it received
			// exercised those fields.
			var parseable bool
			parseable, spec.boolean, spec.multiple = canParse(field.Type)
			if !parseable {
				errs = append(errs, fmt.Sprintf("%s.%s: %s fields are not supported",
					t.Name(), field.Name, field.Type.String()))
				return false
			}

			// Look at the tag
			if tag != "" {
				for _, key := range strings.Split(tag, ",") {
					key = strings.TrimLeft(key, " ")
					var value string
					if pos := strings.Index(key, ":"); pos != -1 {
						value = key[pos+1:]
						key = key[:pos]
					}

					switch {
					case strings.HasPrefix(key, "---"):
						errs = append(errs, fmt.Sprintf("%s.%s: too many hyphens", t.Name(), field.Name))
					case strings.HasPrefix(key, "--"):
						spec.long = key[2:]
					case strings.HasPrefix(key, "-"):
						if len(key) != 2 {
							errs = append(errs, fmt.Sprintf("%s.%s: short arguments must be one character only",
								t.Name(), field.Name))
							return false
						}
						spec.short = key[1:]
					case key == "required":
						spec.required = true
					case key == "positional":
						spec.positional = true
					case key == "separate":
						spec.separate = true
					case key == "help": // deprecated
						spec.help = value
					case key == "env":
						// Use override name if provided
						if value != "" {
							spec.env = value
						} else {
							spec.env = strings.ToUpper(field.Name)
						}
					default:
						errs = append(errs, fmt.Sprintf("unrecognized tag '%s' on field %s", key, tag))
						return false
					}
				}
			}
			p.specs = append(p.specs, &spec)

			// if this was an embedded field then we already returned true up above
			return false
		})

		if len(errs) > 0 {
			return nil, errors.New(strings.Join(errs, "\n"))
		}
	}
	if p.config.Program == "" {
		p.config.Program = "program"
		if len(os.Args) > 0 {
			p.config.Program = filepath.Base(os.Args[0])
		}
	}
	return &p, nil
}
func NewParser(config Config, dests ...interface{}) (*Parser, error) {
	p := Parser{
		config: config,
	}
	for _, dest := range dests {
		if dest, ok := dest.(Versioned); ok {
			p.version = dest.Version()
		}
		if dest, ok := dest.(Described); ok {
			p.description = dest.Description()
		}
		v := reflect.ValueOf(dest)
		if v.Kind() != reflect.Ptr {
			panic(fmt.Sprintf("%s is not a pointer (did you forget an ampersand?)", v.Type()))
		}
		v = v.Elem()
		if v.Kind() != reflect.Struct {
			panic(fmt.Sprintf("%T is not a struct pointer", dest))
		}

		var errs []string
		walkFields(v, func(field reflect.StructField, val reflect.Value, t reflect.Type) bool {
			
			tag := field.Tag.Get("arg")
			if tag == "-" {
				return false
			}

			
			if field.Anonymous && field.Type.Kind() == reflect.Struct {
				return true
			}

			spec := spec{
				long: strings.ToLower(field.Name),
				dest: val,
			}

			help, exists := field.Tag.Lookup("help")
			if exists {
				spec.help = help
			}

			
			
			
			
			var parseable bool
			parseable, spec.boolean, spec.multiple = canParse(field.Type)
			if !parseable {
				errs = append(errs, fmt.Sprintf("%s.%s: %s fields are not supported",
					t.Name(), field.Name, field.Type.String()))
				return false
			}

			
			if tag != "" {
				for _, key := range strings.Split(tag, ",") {
					key = strings.TrimLeft(key, " ")
					var value string
					if pos := strings.Index(key, ":"); pos != -1 {
						value = key[pos+1:]
						key = key[:pos]
					}

					switch {
					case strings.HasPrefix(key, "---"):
						errs = append(errs, fmt.Sprintf("%s.%s: too many hyphens", t.Name(), field.Name))
					case strings.HasPrefix(key, "--"):
						spec.long = key[2:]
					case strings.HasPrefix(key, "-"):
						if len(key) != 2 {
							errs = append(errs, fmt.Sprintf("%s.%s: short arguments must be one character only",
								t.Name(), field.Name))
							return false
						}
						spec.short = key[1:]
					case key == "required":
						spec.required = true
					case key == "positional":
						spec.positional = true
					case key == "separate":
						spec.separate = true
					case key == "help": 
						spec.help = value
					case key == "env":
						
						if value != "" {
							spec.env = value
						} else {
							spec.env = strings.ToUpper(field.Name)
						}
					default:
						errs = append(errs, fmt.Sprintf("unrecognized tag '%s' on field %s", key, tag))
						return false
					}
				}
			}
			p.specs = append(p.specs, &spec)

			
			return false
		})

		if len(errs) > 0 {
			return nil, errors.New(strings.Join(errs, "\n"))
		}
	}
	if p.config.Program == "" {
		p.config.Program = "program"
		if len(os.Args) > 0 {
			p.config.Program = filepath.Base(os.Args[0])
		}
	}
	return &p, nil
}
func NewParser ( config Config , dests ... interface { } ) ( * Parser , error ) { p := Parser { config : config , } for _ , dest := range dests { if dest , ok := dest . ( Versioned ) ; ok { p . version = dest . Version ( ) } if dest , ok := dest . ( Described ) ; ok { p . description = dest . Description ( ) } v := reflect . ValueOf ( dest ) if v . Kind ( ) != reflect . Ptr { panic ( fmt . Sprintf ( " " , v . Type ( ) ) ) } v = v . Elem ( ) if v . Kind ( ) != reflect . Struct { panic ( fmt . Sprintf ( " " , dest ) ) } var errs [ ] string walkFields ( v , func ( field reflect . StructField , val reflect . Value , t reflect . Type ) bool { // Check for the ignore switch in the tag tag := field . Tag . Get ( " " ) if tag == " " { return false } // If this is an embedded struct then recurse into its fields if field . Anonymous && field . Type . Kind ( ) == reflect . Struct { return true } spec := spec { long : strings . ToLower ( field . Name ) , dest : val , } help , exists := field . Tag . Lookup ( " " ) if exists { spec . help = help } // Check whether this field is supported. It's good to do this here rather than // wait until ParseValue because it means that a program with invalid argument // fields will always fail regardless of whether the arguments it received // exercised those fields. var parseable bool parseable , spec . boolean , spec . multiple = canParse ( field . Type ) if ! parseable { errs = append ( errs , fmt . Sprintf ( " " , t . Name ( ) , field . Name , field . Type . String ( ) ) ) return false } // Look at the tag if tag != " " { for _ , key := range strings . Split ( tag , " " ) { key = strings . TrimLeft ( key , " " ) var value string if pos := strings . Index ( key , " " ) ; pos != - 1 { value = key [ pos + 1 : ] key = key [ : pos ] } switch { case strings . HasPrefix ( key , " " ) : errs = append ( errs , fmt . Sprintf ( " " , t . Name ( ) , field . Name ) ) case strings . HasPrefix ( key , " " ) : spec . long = key [ 2 : ] case strings . HasPrefix ( key , " " ) : if len ( key ) != 2 { errs = append ( errs , fmt . Sprintf ( " " , t . Name ( ) , field . Name ) ) return false } spec . short = key [ 1 : ] case key == " " : spec . required = true case key == " " : spec . positional = true case key == " " : spec . separate = true case key == " " : // deprecated spec . help = value case key == " " : // Use override name if provided if value != " " { spec . env = value } else { spec . env = strings . ToUpper ( field . Name ) } default : errs = append ( errs , fmt . Sprintf ( " " , key , tag ) ) return false } } } p . specs = append ( p . specs , & spec ) // if this was an embedded field then we already returned true up above return false } ) if len ( errs ) > 0 { return nil , errors . New ( strings . Join ( errs , " \n " ) ) } } if p . config . Program == " " { p . config . Program = " " if len ( os . Args ) > 0 { p . config . Program = filepath . Base ( os . Args [ 0 ] ) } } return & p , nil }
// NewParser constructs a parser from a list of destination structs
NewParser constructs a parser from a list of destination structs