From 30befae91a472e767b021961620ac0d93e6ff11d Mon Sep 17 00:00:00 2001 From: Alex Flint Date: Sun, 1 Nov 2015 00:13:23 -0700 Subject: [PATCH] move more stuff over to the parser struct --- parse.go | 85 +++++++++++++++++++++++--------------------------------- usage.go | 30 ++++---------------- 2 files changed, 40 insertions(+), 75 deletions(-) diff --git a/parse.go b/parse.go index 119efbd..dfa3421 100644 --- a/parse.go +++ b/parse.go @@ -3,9 +3,7 @@ package arg import ( "errors" "fmt" - "io" "os" - "path/filepath" "reflect" "strconv" "strings" @@ -23,10 +21,10 @@ type spec struct { wasPresent bool } -// Parse returns this value to indicate that -h or --help were provided +// ErrHelp indicates that -h or --help were provided var ErrHelp = errors.New("help requested by user") -// MustParse processes command line arguments and exits upon failure. +// MustParse processes command line arguments and exits upon failure func MustParse(dest ...interface{}) { p, err := NewParser(dest...) if err != nil { @@ -34,19 +32,20 @@ func MustParse(dest ...interface{}) { os.Exit(1) } err = p.Parse(os.Args[1:]) + if err == ErrHelp { + p.WriteUsage(os.Stdout) + os.Exit(0) + } if err != nil { - fmt.Println(err) - writeUsage(os.Stdout, filepath.Base(os.Args[0]), p.spec) - os.Exit(1) + p.Fail(err.Error()) } } -// Parse processes command line arguments and stores them in dest. +// Parse processes command line arguments and stores them in dest func Parse(dest ...interface{}) error { p, err := NewParser(dest...) if err != nil { - fmt.Println(err) - os.Exit(1) + return err } return p.Parse(os.Args[1:]) } @@ -57,44 +56,7 @@ type Parser struct { } // NewParser constructs a parser from a list of destination structs -func NewParser(dest ...interface{}) (*Parser, error) { - spec, err := extractSpec(dest...) - if err != nil { - return nil, err - } - return &Parser{spec: spec}, nil -} - -// Parse processes the given command line option, storing the results in the field -// of the structs from which NewParser was constructed -func (p *Parser) Parse(args []string) error { - // If -h or --help were specified then print usage - for _, arg := range args { - if arg == "-h" || arg == "--help" { - return ErrHelp - } - if arg == "--" { - break - } - } - - // Process all command line arguments - err := process(p.spec, args) - if err != nil { - return err - } - - // Validate - return validate(p.spec) -} - -// WriteUsage writes usage information to the given writer -func (p *Parser) WriteUsage(w io.Writer) { - writeUsage(w, filepath.Base(os.Args[0]), p.spec) -} - -// extractSpec gets specifications for each argument from the tags in a struct -func extractSpec(dests ...interface{}) ([]*spec, error) { +func NewParser(dests ...interface{}) (*Parser, error) { var specs []*spec for _, dest := range dests { v := reflect.ValueOf(dest) @@ -169,10 +131,33 @@ func extractSpec(dests ...interface{}) ([]*spec, error) { specs = append(specs, &spec) } } - return specs, nil + return &Parser{spec: specs}, nil } -// process goes through arguments the arguments one-by-one, parses them, and assigns the result to +// Parse processes the given command line option, storing the results in the field +// of the structs from which NewParser was constructed +func (p *Parser) Parse(args []string) error { + // If -h or --help were specified then print usage + for _, arg := range args { + if arg == "-h" || arg == "--help" { + return ErrHelp + } + if arg == "--" { + break + } + } + + // Process all command line arguments + err := process(p.spec, args) + if err != nil { + return err + } + + // Validate + return validate(p.spec) +} + +// process goes through arguments one-by-one, parses them, and assigns the result to // the underlying struct field func process(specs []*spec, args []string) error { // construct a map from --option to spec diff --git a/usage.go b/usage.go index fdc2248..689da73 100644 --- a/usage.go +++ b/usage.go @@ -9,37 +9,17 @@ import ( "strings" ) -// Usage prints usage information to stdout and exits with status zero -func Usage(dest ...interface{}) { - if err := WriteUsage(os.Stdout, dest...); err != nil { - fmt.Println(err) - } - os.Exit(0) -} - // Fail prints usage information to stdout and exits with non-zero status -func Fail(msg string, dest ...interface{}) { +func (p *Parser) Fail(msg string) { fmt.Println(msg) - if err := WriteUsage(os.Stdout, dest...); err != nil { - fmt.Println(err) - } + p.WriteUsage(os.Stdout) os.Exit(1) } // WriteUsage writes usage information to the given writer -func WriteUsage(w io.Writer, dest ...interface{}) error { - spec, err := extractSpec(dest...) - if err != nil { - return err - } - writeUsage(w, filepath.Base(os.Args[0]), spec) - return nil -} - -// writeUsage writes usage information to the given writer -func writeUsage(w io.Writer, cmd string, specs []*spec) { +func (p *Parser) WriteUsage(w io.Writer) { var positionals, options []*spec - for _, spec := range specs { + for _, spec := range p.spec { if spec.positional { positionals = append(positionals, spec) } else { @@ -47,7 +27,7 @@ func writeUsage(w io.Writer, cmd string, specs []*spec) { } } - fmt.Fprint(w, "usage: %s ", cmd) + fmt.Fprintf(w, "usage: %s ", filepath.Base(os.Args[0])) // write the option component of the one-line usage message for _, spec := range options {