Custom parsers implementing encoding.TextMarshaler() can have default values printed via --help
This commit is contained in:
parent
0cc8e30fd6
commit
d4cc703210
18
README.md
18
README.md
|
@ -265,15 +265,33 @@ func (n *NameDotName) UnmarshalText(b []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// optional, implement in case you want to use defaults
|
||||||
|
func (n *NameDotName) MarshalText() (text []byte, err error) {
|
||||||
|
text = []byte(fmt.Sprintf("%s.%s", n.Head, n.Tail))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var args struct {
|
var args struct {
|
||||||
Name *NameDotName
|
Name *NameDotName
|
||||||
}
|
}
|
||||||
|
// set default
|
||||||
|
args.Name = &NameDotName{"file", "txt"}
|
||||||
arg.MustParse(&args)
|
arg.MustParse(&args)
|
||||||
fmt.Printf("%#v\n", args.Name)
|
fmt.Printf("%#v\n", args.Name)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
```shell
|
```shell
|
||||||
|
$ ./example --help
|
||||||
|
Usage: test [--name NAME]
|
||||||
|
|
||||||
|
Options:
|
||||||
|
--name NAME [default: file.txt]
|
||||||
|
--help, -h display this help and exit
|
||||||
|
|
||||||
|
$ ./example
|
||||||
|
&main.NameDotName{Head:"file", Tail:"txt"}
|
||||||
|
|
||||||
$ ./example --name=foo.bar
|
$ ./example --name=foo.bar
|
||||||
&main.NameDotName{Head:"foo", Tail:"bar"}
|
&main.NameDotName{Head:"foo", Tail:"bar"}
|
||||||
|
|
||||||
|
|
11
usage.go
11
usage.go
|
@ -6,6 +6,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
"encoding"
|
||||||
)
|
)
|
||||||
|
|
||||||
// the width of the left column
|
// the width of the left column
|
||||||
|
@ -134,7 +135,15 @@ func printOption(w io.Writer, spec *spec) {
|
||||||
if v.IsValid() {
|
if v.IsValid() {
|
||||||
z := reflect.Zero(v.Type())
|
z := reflect.Zero(v.Type())
|
||||||
if (v.Type().Comparable() && z.Type().Comparable() && v.Interface() != z.Interface()) || v.Kind() == reflect.Slice && !v.IsNil() {
|
if (v.Type().Comparable() && z.Type().Comparable() && v.Interface() != z.Interface()) || v.Kind() == reflect.Slice && !v.IsNil() {
|
||||||
fmt.Fprintf(w, " [default: %v]", v)
|
if scalar, ok := v.Interface().(encoding.TextMarshaler); ok {
|
||||||
|
if value, err := scalar.MarshalText(); err != nil {
|
||||||
|
fmt.Fprintf(w, " [default: error: %v]", err)
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(w, " [default: %v]", string(value))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(w, " [default: %v]", v)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fmt.Fprint(w, "\n")
|
fmt.Fprint(w, "\n")
|
||||||
|
|
|
@ -7,12 +7,34 @@ import (
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
"strings"
|
||||||
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestWriteUsage(t *testing.T) {
|
type NameDotName struct {
|
||||||
expectedUsage := "Usage: example [--name NAME] [--value VALUE] [--verbose] [--dataset DATASET] [--optimize OPTIMIZE] [--ids IDS] [--values VALUES] [--workers WORKERS] INPUT [OUTPUT [OUTPUT ...]]\n"
|
Head, Tail string
|
||||||
|
}
|
||||||
|
|
||||||
expectedHelp := `Usage: example [--name NAME] [--value VALUE] [--verbose] [--dataset DATASET] [--optimize OPTIMIZE] [--ids IDS] [--values VALUES] [--workers WORKERS] INPUT [OUTPUT [OUTPUT ...]]
|
func (n *NameDotName) UnmarshalText(b []byte) error {
|
||||||
|
s := string(b)
|
||||||
|
pos := strings.Index(s, ".")
|
||||||
|
if pos == -1 {
|
||||||
|
return fmt.Errorf("missing period in %s", s)
|
||||||
|
}
|
||||||
|
n.Head = s[:pos]
|
||||||
|
n.Tail = s[pos+1:]
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NameDotName) MarshalText() (text []byte, err error) {
|
||||||
|
text = []byte(fmt.Sprintf("%s.%s", n.Head, n.Tail))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWriteUsage(t *testing.T) {
|
||||||
|
expectedUsage := "Usage: example [--name NAME] [--value VALUE] [--verbose] [--dataset DATASET] [--optimize OPTIMIZE] [--ids IDS] [--values VALUES] [--workers WORKERS] [--file FILE] INPUT [OUTPUT [OUTPUT ...]]\n"
|
||||||
|
|
||||||
|
expectedHelp := `Usage: example [--name NAME] [--value VALUE] [--verbose] [--dataset DATASET] [--optimize OPTIMIZE] [--ids IDS] [--values VALUES] [--workers WORKERS] [--file FILE] INPUT [OUTPUT [OUTPUT ...]]
|
||||||
|
|
||||||
Positional arguments:
|
Positional arguments:
|
||||||
INPUT
|
INPUT
|
||||||
|
@ -29,6 +51,7 @@ Options:
|
||||||
--values VALUES Values [default: [3.14 42 256]]
|
--values VALUES Values [default: [3.14 42 256]]
|
||||||
--workers WORKERS, -w WORKERS
|
--workers WORKERS, -w WORKERS
|
||||||
number of workers to start
|
number of workers to start
|
||||||
|
--file FILE, -f FILE File with mandatory extension [default: scratch.txt]
|
||||||
--help, -h display this help and exit
|
--help, -h display this help and exit
|
||||||
`
|
`
|
||||||
var args struct {
|
var args struct {
|
||||||
|
@ -42,11 +65,13 @@ Options:
|
||||||
Ids []int64 `help:"Ids"`
|
Ids []int64 `help:"Ids"`
|
||||||
Values []float64 `help:"Values"`
|
Values []float64 `help:"Values"`
|
||||||
Workers int `arg:"-w,env:WORKERS" help:"number of workers to start"`
|
Workers int `arg:"-w,env:WORKERS" help:"number of workers to start"`
|
||||||
|
File *NameDotName `arg:"-f" help:"File with mandatory extension"`
|
||||||
}
|
}
|
||||||
args.Name = "Foo Bar"
|
args.Name = "Foo Bar"
|
||||||
args.Value = 42
|
args.Value = 42
|
||||||
args.Values = []float64{3.14, 42, 256}
|
args.Values = []float64{3.14, 42, 256}
|
||||||
p, err := NewParser(Config{}, &args)
|
args.File = &NameDotName{"scratch", "txt"}
|
||||||
|
p, err := NewParser(Config{"example"}, &args)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
os.Args[0] = "example"
|
os.Args[0] = "example"
|
||||||
|
|
Loading…
Reference in New Issue