From d4c2b35b2ef5b67c3ec6f904cea0dff806d51e2c Mon Sep 17 00:00:00 2001 From: Kenneth Shaw Date: Fri, 3 Mar 2017 19:12:17 +0700 Subject: Adding separate tag option As outlined in #49, there is a need to mimic the behavior of other applications by interweaving positional and non-positional parameters. This change adds the 'separate' option that will force a arg of type []string to only read the next supplied value. For example, when dealing with the following arg type: var MyArgs struct { Pos []string `arg:"positional"` Separate []string `arg:"-s,separate"` } This commit will parse the following command line: ./app pos1 pos2 -s=separate1 -s=separate2 pos3 -s=separate3 pos4 Such that MyArgs.Pos will be [pos1 pos2 pos3 pos4] and MyArgs.Separate will be [separate1 separate2 separate3]. Unit tests for the above have also been written and are included in this commit, as well as the addition of a section to README.md and an example func in example_test.go. Fixes #49 --- parse.go | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'parse.go') diff --git a/parse.go b/parse.go index 60f35ee..4f62c60 100644 --- a/parse.go +++ b/parse.go @@ -20,6 +20,7 @@ type spec struct { multiple bool required bool positional bool + separate bool help string env string wasPresent bool @@ -189,6 +190,8 @@ func NewParser(config Config, dests ...interface{}) (*Parser, error) { spec.required = true case key == "positional": spec.positional = true + case key == "separate": + spec.separate = true case key == "help": spec.help = value case key == "env": @@ -314,11 +317,14 @@ func process(specs []*spec, args []string) error { for i+1 < len(args) && !isFlag(args[i+1]) { values = append(values, args[i+1]) i++ + if spec.separate { + break + } } } else { values = append(values, value) } - err := setSlice(spec.dest, values) + err := setSlice(spec.dest, values, !spec.separate) if err != nil { return fmt.Errorf("error processing %s: %v", arg, err) } @@ -350,7 +356,7 @@ func process(specs []*spec, args []string) error { for _, spec := range specs { if spec.positional { if spec.multiple { - err := setSlice(spec.dest, positionals) + err := setSlice(spec.dest, positionals, true) if err != nil { return fmt.Errorf("error processing %s: %v", spec.long, err) } @@ -388,7 +394,7 @@ func validate(spec []*spec) error { } // parse a value as the appropriate type and store it in the struct -func setSlice(dest reflect.Value, values []string) error { +func setSlice(dest reflect.Value, values []string, trunc bool) error { if !dest.CanSet() { return fmt.Errorf("field is not writable") } @@ -401,7 +407,7 @@ func setSlice(dest reflect.Value, values []string) error { } // Truncate the dest slice in case default values exist - if !dest.IsNil() { + if trunc && !dest.IsNil() { dest.SetLen(0) } -- cgit v1.2.3