Content-Length: 12998 | pFad | http://github.com/akamensky/argparse/commit/6876ef20deacf93ca59bdea6d4dc6addd73c70d5.patch
2F
From 6876ef20deacf93ca59bdea6d4dc6addd73c70d5 Mon Sep 17 00:00:00 2001
From: Densest Void
Date: Tue, 28 Jan 2020 23:57:51 -0500
Subject: [PATCH] Custom help (#50)
* Finishes addressing issue #29
Adds a Settings struct for creating parsers/commands with
NewParserWithSettings or NewCommandWithSettings.
Settings
HelpDisabled - defaults false, set true to not generate a help
argument for parser/command
HelpSname - short name for the parser/command help argument.
Can be left empty
HelpLname - long name for the parser/command help argument.
Leaving empty forces use of -h/--help when
HelpDisabled is false
NoExitOnHelp - defaults false, set true to not exit on help
argument being parsed
Should resolve all outstanding help argument issues.
* Finishing Issue #29
Fixed merge conflict error due to check function return type change confusion.
* Updated Settings Object to multiple function calls
Added functions:
DisableHelp
SetHelp
ExitOnHelp
Added Command.exitOnHelp
Added more tests to increase code coverage
* Updated no help example
---
argparse.go | 31 ++-
argparse_examples_test.go | 4 +-
argparse_test.go | 185 +++++++++++++++++-
argument.go | 20 +-
command.go | 12 +-
.../help-argument-names.go | 19 ++
examples/help-no-exit/help-no-exit.go | 20 ++
examples/no-help/no-help.go | 20 ++
8 files changed, 292 insertions(+), 19 deletions(-)
create mode 100644 examples/help-argument-names/help-argument-names.go
create mode 100644 examples/help-no-exit/help-no-exit.go
create mode 100644 examples/no-help/no-help.go
diff --git a/argparse.go b/argparse.go
index 9dfc7e8..a743ade 100644
--- a/argparse.go
+++ b/argparse.go
@@ -23,6 +23,7 @@ type Command struct {
happened bool
parent *Command
HelpFunc func(c *Command, msg interface{}) string
+ exitOnHelp bool
}
// GetName exposes Command's name field
@@ -109,7 +110,8 @@ func NewParser(name string, description string) *Parser {
p.args = make([]*arg, 0)
p.commands = make([]*Command, 0)
- p.help()
+ p.help("h", "help")
+ p.exitOnHelp = true
p.HelpFunc = (*Command).Usage
return p
@@ -128,8 +130,7 @@ func (o *Command) NewCommand(name string, description string) *Command {
c.description = description
c.parsed = false
c.parent = o
-
- c.help()
+ c.exitOnHelp = o.exitOnHelp
if o.commands == nil {
o.commands = make([]*Command, 0)
@@ -140,6 +141,30 @@ func (o *Command) NewCommand(name string, description string) *Command {
return c
}
+// DisableHelp removes any help arguments from the commands list of arguments
+// This prevents prevents help from being parsed or invoked from the argument list
+func (o *Parser) DisableHelp() {
+ for i, arg := range o.args {
+ if _, ok := arg.result.(*help); ok {
+ o.args = append(o.args[:i], o.args[i+1:]...)
+ }
+ }
+}
+
+// ExitOnHelp sets the exitOnHelp variable of Parser
+func (o *Command) ExitOnHelp(b bool) {
+ o.exitOnHelp = b
+ for _, c := range o.commands {
+ c.ExitOnHelp(b)
+ }
+}
+
+// SetHelp removes the previous help argument, and creates a new one with the desired sname/lname
+func (o *Parser) SetHelp(sname, lname string) {
+ o.DisableHelp()
+ o.help(sname, lname)
+}
+
// Flag Creates new flag type of argument, which is boolean value showing if argument was provided or not.
// Takes short name, long name and pointer to options (optional).
// Short name must be single character, but can be omitted by giving empty string.
diff --git a/argparse_examples_test.go b/argparse_examples_test.go
index b405ccd..1d38b6f 100644
--- a/argparse_examples_test.go
+++ b/argparse_examples_test.go
@@ -1,6 +1,8 @@
package argparse
-import "fmt"
+import (
+ "fmt"
+)
func ExampleCommand_Help() {
parser := NewParser("parser", "")
diff --git a/argparse_test.go b/argparse_test.go
index 3283bc1..cf6497d 100644
--- a/argparse_test.go
+++ b/argparse_test.go
@@ -2282,9 +2282,192 @@ func TestUsageStringer(t *testing.T) {
}
}
-func TestNewParserHelpFuncDefault(t *testing.T) {
+func TestParserHelpFuncDefault(t *testing.T) {
parser := NewParser("parser", "")
if parser.HelpFunc == nil || parser.Help(nil) != parser.Usage(nil) {
t.Errorf("HelpFunc should default to Usage function")
}
}
+
+func TestCommandHelpFuncDefault(t *testing.T) {
+ parser := NewParser("parser", "")
+ command := parser.NewCommand("command", "")
+ if command.HelpFunc != nil {
+ t.Errorf("HelpFunc should default to Usage function")
+ }
+}
+
+func TestCommandHelpFuncDefaultToParent(t *testing.T) {
+ parser := NewParser("parser", "")
+ command := parser.NewCommand("command", "")
+
+ parser.HelpFunc = func(c *Command, msg interface{}) string {
+ return "testing"
+ }
+
+ if command.Help(nil) == command.Usage(nil) || command.Help(nil) != parser.Help(nil) {
+ t.Errorf("command HelpFunc should default to parent function")
+ }
+}
+
+func TestParserExitOnHelpTrue(t *testing.T) {
+ exited := false
+ exit = func(n int) {
+ exited = true
+ }
+
+ parser := NewParser("parser", "")
+
+ print = func(...interface{}) (int, error) {
+ return 0, nil
+ }
+
+ if err := parser.Parse([]string{"parser", "-h"}); err == nil {
+ if !exited {
+ t.Errorf("Parsing help should have invoked os.Exit")
+ }
+ } else {
+ t.Error(err)
+ }
+}
+
+func TestParserExitOnHelpFalse(t *testing.T) {
+ exited := false
+ exit = func(n int) {
+ exited = true
+ }
+
+ parser := NewParser("parser", "")
+ parser.ExitOnHelp(false)
+
+ print = func(...interface{}) (int, error) {
+ return 0, nil
+ }
+
+ if err := parser.Parse([]string{"parser", "-h"}); exited {
+ t.Errorf("Parsing help should not have invoked os.Exit")
+ } else if err != nil {
+ t.Error(err)
+ }
+}
+
+func TestParserDisableHelp(t *testing.T) {
+ parser := NewParser("parser", "")
+ parser.DisableHelp()
+ if len(parser.args) > 0 {
+ t.Errorf("Parser should not have any arguments")
+ }
+
+ print = func(...interface{}) (int, error) {
+ return 0, nil
+ }
+
+ if err := parser.Parse([]string{"parser", "-h"}); err == nil {
+ t.Errorf("Parsing should fail, help argument shouldn't exist")
+ }
+}
+
+func TestParserSetHelp(t *testing.T) {
+ sname, lname := "x", "xyz"
+ parser := NewParser("parser", "")
+ parser.SetHelp(sname, lname)
+ if len(parser.args) != 1 {
+ t.Errorf("Parser should have one argument:\n%s", parser.Help(nil))
+ }
+ arg := parser.args[0]
+ if _, ok := arg.result.(*help); !ok {
+ t.Errorf("Argument should be %T, is %T", help{}, arg.result)
+ }
+ if arg.sname != sname {
+ t.Errorf("Argument short name should be %s, is %s", sname, arg.sname)
+ }
+ if arg.lname != lname {
+ t.Errorf("Argument long name should be %s, is %s", lname, arg.lname)
+ }
+}
+
+func TestCommandExitOnHelpTrue(t *testing.T) {
+ exited := false
+ exit = func(n int) {
+ exited = true
+ }
+
+ parser := NewParser("parser", "")
+ parser.NewCommand("command", "")
+
+ print = func(...interface{}) (int, error) {
+ return 0, nil
+ }
+
+ if err := parser.Parse([]string{"parser", "command", "-h"}); exited {
+ if err != nil {
+ t.Error(err)
+ }
+ } else {
+ t.Errorf("Parsing help should have invoked os.Exit")
+ }
+}
+
+func TestCommandExitOnHelpFalse(t *testing.T) {
+ exited := false
+ exit = func(n int) {
+ exited = true
+ }
+
+ parser := NewParser("parser", "")
+ parser.NewCommand("command", "")
+ parser.ExitOnHelp(false)
+
+ print = func(...interface{}) (int, error) {
+ return 0, nil
+ }
+
+ if err := parser.Parse([]string{"parser", "command", "-h"}); exited {
+ t.Error("Parsing help should not have exited")
+ } else if err != nil {
+ t.Error(err)
+ }
+}
+
+func TestCommandDisableHelp(t *testing.T) {
+ parser := NewParser("parser", "")
+ parser.NewCommand("command", "")
+ parser.DisableHelp()
+ if len(parser.args) > 0 {
+ t.Errorf("Parser should not have any arguments")
+ }
+
+ print = func(...interface{}) (int, error) {
+ return 0, nil
+ }
+
+ if err := parser.Parse([]string{"parser", "command", "-h"}); err == nil {
+ t.Errorf("Parsing should fail, help argument shouldn't exist")
+ }
+}
+
+func TestCommandHelpInheritance(t *testing.T) {
+ parser := NewParser("parser", "")
+ command := parser.NewCommand("command", "")
+ parser.ExitOnHelp(false)
+
+ if command.exitOnHelp != false {
+ t.Errorf("Command should inherit exitOnHelp from parent, even after creation")
+ }
+}
+
+func TestCommandHelpSetSnameOnly(t *testing.T) {
+ parser := NewParser("parser", "")
+ parser.SetHelp("q", "")
+
+ arg := parser.args[0]
+
+ _, ok := arg.result.(*help)
+ if !ok {
+ t.Error("Argument should be of help type")
+ }
+
+ if arg.sname != "h" || arg.lname != "help" {
+ t.Error("Help arugment names should have defaulted")
+ }
+}
diff --git a/argument.go b/argument.go
index 34ebda9..01bec7c 100644
--- a/argument.go
+++ b/argument.go
@@ -98,13 +98,6 @@ func (o *arg) checkShortName(argument string) (int, error) {
// For shorthand argument - 0 if there is no occurrences, or count of occurrences.
// Shorthand argument with parametr, mast be the only or last in the argument string.
func (o *arg) check(argument string) (int, error) {
- // Shortcut to showing help
- if argument == "-h" || argument == "--help" {
- helpText := o.parent.Help(nil)
- fmt.Print(helpText)
- os.Exit(0)
- }
-
rez := o.checkLongName(argument)
if rez > 0 {
return rez, nil
@@ -334,13 +327,20 @@ func (o *arg) parseFileList(args []string) error {
return nil
}
+// To overwrite while testing
+// Possibly extend to allow user overriding
+var exit func(int) = os.Exit
+var print func(...interface{}) (int, error) = fmt.Println
+
func (o *arg) parseSomeType(args []string, argCount int) error {
var err error
switch o.result.(type) {
case *help:
- helpText := o.parent.Help(nil)
- fmt.Print(helpText)
- os.Exit(0)
+ print(o.parent.Help(nil))
+ if o.parent.exitOnHelp {
+ exit(0)
+ }
+ //data of bool type is for Flag argument
case *bool:
err = o.parseBool(args)
case *int:
diff --git a/command.go b/command.go
index c6abe3f..da8d7ba 100644
--- a/command.go
+++ b/command.go
@@ -4,13 +4,17 @@ import (
"fmt"
)
-func (o *Command) help() {
+func (o *Command) help(sname, lname string) {
result := &help{}
+ if lname == "" {
+ sname, lname = "h", "help"
+ }
+
a := &arg{
- result: &result,
- sname: "h",
- lname: "help",
+ result: result,
+ sname: sname,
+ lname: lname,
size: 1,
opts: &Options{Help: "Print help information"},
unique: true,
diff --git a/examples/help-argument-names/help-argument-names.go b/examples/help-argument-names/help-argument-names.go
new file mode 100644
index 0000000..e8151d0
--- /dev/null
+++ b/examples/help-argument-names/help-argument-names.go
@@ -0,0 +1,19 @@
+package main
+
+import (
+ "fmt"
+
+ "github.com/akamensky/argparse"
+)
+
+func main() {
+ // Create new parser object
+ parser := argparse.NewParser("help", "Demonstrates changing the help argument names")
+ parser.SetHelp("e", "example")
+ // Create string flag
+ parser.String("s", "string", &argparse.Options{Required: false, Help: "String argument example"})
+ // Create string flag
+ parser.Int("i", "int", &argparse.Options{Required: false, Help: "Integer argument example"})
+ // Use the help function
+ fmt.Print(parser.Parse([]string{"parser", "-e"}))
+}
diff --git a/examples/help-no-exit/help-no-exit.go b/examples/help-no-exit/help-no-exit.go
new file mode 100644
index 0000000..a5b5c55
--- /dev/null
+++ b/examples/help-no-exit/help-no-exit.go
@@ -0,0 +1,20 @@
+package main
+
+import (
+ "fmt"
+
+ "github.com/akamensky/argparse"
+)
+
+func main() {
+ // Create new parser object
+ parser := argparse.NewParser("help", "Demonstrates changing the help argument names")
+ parser.ExitOnHelp(false)
+ // Create string flag
+ parser.String("s", "string", &argparse.Options{Required: false, Help: "String argument example"})
+ // Create string flag
+ parser.Int("i", "int", &argparse.Options{Required: false, Help: "Integer argument example"})
+ // Use the help function
+ fmt.Println(parser.Parse([]string{"parser", "-h"}))
+ fmt.Println("Didn't exit, still printing")
+}
diff --git a/examples/no-help/no-help.go b/examples/no-help/no-help.go
new file mode 100644
index 0000000..422918b
--- /dev/null
+++ b/examples/no-help/no-help.go
@@ -0,0 +1,20 @@
+package main
+
+import (
+ "fmt"
+
+ "github.com/akamensky/argparse"
+)
+
+func main() {
+ // Create new parser object
+ parser := argparse.NewParser("help", "Demonstrates disabing the help arguments")
+ parser.DisableHelp()
+ // Create string flag
+ parser.String("s", "string", &argparse.Options{Required: false, Help: "String argument example"})
+ // Create string flag
+ parser.Int("i", "int", &argparse.Options{Required: false, Help: "Integer argument example"})
+
+ // parsing for -h fails
+ fmt.Println(parser.Parse([]string{"parser", "-h", "--help", "-s", "testing", "-i", "5"}))
+}
--- a PPN by Garber Painting Akron. With Image Size Reduction included!Fetched URL: http://github.com/akamensky/argparse/commit/6876ef20deacf93ca59bdea6d4dc6addd73c70d5.patch
Alternative Proxies:
Alternative Proxy
pFad Proxy
pFad v3 Proxy
pFad v4 Proxy