Skip to content

Commit

Permalink
Remove NewApp func
Browse files Browse the repository at this point in the history
in favor of focusing on declarative API.

Supports #1586
  • Loading branch information
meatballhat committed Dec 18, 2022
1 parent 859b1e3 commit 7919d3a
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 171 deletions.
18 changes: 1 addition & 17 deletions app.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ var (
SuggestDidYouMeanTemplate string = suggestDidYouMeanTemplate
)

// App is the main structure of a cli application. It is recommended that
// an app be created with the cli.NewApp() function
// App is the main structure of a cli application.
type App struct {
// The name of the program. Defaults to path.Base(os.Args[0])
Name string
Expand Down Expand Up @@ -126,21 +125,6 @@ type SuggestFlagFunc func(flags []Flag, provided string, hideHelp bool) string

type SuggestCommandFunc func(commands []*Command, provided string) string

// NewApp creates a new cli Application with some reasonable defaults for Name,
// Usage, Version and Action.
func NewApp() *App {
return &App{
Name: filepath.Base(os.Args[0]),
Usage: "A new cli application",
UsageText: "",
ShellComplete: DefaultAppComplete,
Action: helpCommand.Action,
Reader: os.Stdin,
Writer: os.Stdout,
ErrWriter: os.Stderr,
}
}

// Setup runs initialization code to ensure all data structures are ready for
// `Run` or inspection prior to `Run`. It is internally called by `Run`, but
// will return early if setup has already happened.
Expand Down
187 changes: 97 additions & 90 deletions app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,17 +234,18 @@ func ExampleApp_Run_bashComplete_withShortFlag() {
os.Setenv("SHELL", "bash")
os.Args = []string{"greet", "-", "--generate-shell-completion"}

app := NewApp()
app.Name = "greet"
app.EnableShellCompletion = true
app.Flags = []Flag{
&IntFlag{
Name: "other",
Aliases: []string{"o"},
},
&StringFlag{
Name: "xyz",
Aliases: []string{"x"},
app := &App{
Name: "greet",
EnableShellCompletion: true,
Flags: []Flag{
&IntFlag{
Name: "other",
Aliases: []string{"o"},
},
&StringFlag{
Name: "xyz",
Aliases: []string{"x"},
},
},
}

Expand All @@ -262,23 +263,24 @@ func ExampleApp_Run_bashComplete_withLongFlag() {
os.Setenv("SHELL", "bash")
os.Args = []string{"greet", "--s", "--generate-shell-completion"}

app := NewApp()
app.Name = "greet"
app.EnableShellCompletion = true
app.Flags = []Flag{
&IntFlag{
Name: "other",
Aliases: []string{"o"},
},
&StringFlag{
Name: "xyz",
Aliases: []string{"x"},
},
&StringFlag{
Name: "some-flag,s",
},
&StringFlag{
Name: "similar-flag",
app := &App{
Name: "greet",
EnableShellCompletion: true,
Flags: []Flag{
&IntFlag{
Name: "other",
Aliases: []string{"o"},
},
&StringFlag{
Name: "xyz",
Aliases: []string{"x"},
},
&StringFlag{
Name: "some-flag,s",
},
&StringFlag{
Name: "similar-flag",
},
},
}

Expand All @@ -292,26 +294,27 @@ func ExampleApp_Run_bashComplete_withMultipleLongFlag() {
os.Setenv("SHELL", "bash")
os.Args = []string{"greet", "--st", "--generate-shell-completion"}

app := NewApp()
app.Name = "greet"
app.EnableShellCompletion = true
app.Flags = []Flag{
&IntFlag{
Name: "int-flag",
Aliases: []string{"i"},
},
&StringFlag{
Name: "string",
Aliases: []string{"s"},
},
&StringFlag{
Name: "string-flag-2",
},
&StringFlag{
Name: "similar-flag",
},
&StringFlag{
Name: "some-flag",
app := &App{
Name: "greet",
EnableShellCompletion: true,
Flags: []Flag{
&IntFlag{
Name: "int-flag",
Aliases: []string{"i"},
},
&StringFlag{
Name: "string",
Aliases: []string{"s"},
},
&StringFlag{
Name: "string-flag-2",
},
&StringFlag{
Name: "similar-flag",
},
&StringFlag{
Name: "some-flag",
},
},
}

Expand Down Expand Up @@ -364,26 +367,27 @@ func ExampleApp_Run_zshComplete() {
os.Args = []string{"greet", "--generate-shell-completion"}
_ = os.Setenv("SHELL", "/usr/bin/zsh")

app := NewApp()
app.Name = "greet"
app.EnableShellCompletion = true
app.Commands = []*Command{
{
Name: "describeit",
Aliases: []string{"d"},
Usage: "use it to see a description",
Description: "This is how we describe describeit the function",
Action: func(*Context) error {
fmt.Printf("i like to describe things")
return nil
},
}, {
Name: "next",
Usage: "next example",
Description: "more stuff to see when generating bash completion",
Action: func(*Context) error {
fmt.Printf("the next example")
return nil
app := &App{
Name: "greet",
EnableShellCompletion: true,
Commands: []*Command{
{
Name: "describeit",
Aliases: []string{"d"},
Usage: "use it to see a description",
Description: "This is how we describe describeit the function",
Action: func(*Context) error {
fmt.Printf("i like to describe things")
return nil
},
}, {
Name: "next",
Usage: "next example",
Description: "more stuff to see when generating bash completion",
Action: func(*Context) error {
fmt.Printf("the next example")
return nil
},
},
},
}
Expand All @@ -406,13 +410,14 @@ func ExampleApp_Run_sliceValues() {
"--int64Sclice", "13,14", "--int64Sclice", "15,16",
"--intSclice", "13,14", "--intSclice", "15,16",
}
app := NewApp()
app.Name = "multi_values"
app.Flags = []Flag{
&StringSliceFlag{Name: "stringSclice"},
&Float64SliceFlag{Name: "float64Sclice"},
&Int64SliceFlag{Name: "int64Sclice"},
&IntSliceFlag{Name: "intSclice"},
app := &App{
Name: "multi_values",
Flags: []Flag{
&StringSliceFlag{Name: "stringSclice"},
&Float64SliceFlag{Name: "float64Sclice"},
&Int64SliceFlag{Name: "int64Sclice"},
&IntSliceFlag{Name: "intSclice"},
},
}
app.Action = func(ctx *Context) error {
for i, v := range ctx.FlagNames() {
Expand All @@ -438,19 +443,20 @@ func ExampleApp_Run_mapValues() {
"multi_values",
"--stringMap", "parsed1=parsed two", "--stringMap", "parsed3=",
}
app := NewApp()
app.Name = "multi_values"
app.Flags = []Flag{
&StringMapFlag{Name: "stringMap"},
}
app.Action = func(ctx *Context) error {
for i, v := range ctx.FlagNames() {
fmt.Printf("%d-%s %#v\n", i, v, ctx.StringMap(v))
}
fmt.Printf("notfound %#v\n", ctx.StringMap("notfound"))
err := ctx.Err()
fmt.Println("error:", err)
return err
app := &App{
Name: "multi_values",
Flags: []Flag{
&StringMapFlag{Name: "stringMap"},
},
Action: func(ctx *Context) error {
for i, v := range ctx.FlagNames() {
fmt.Printf("%d-%s %#v\n", i, v, ctx.StringMap(v))
}
fmt.Printf("notfound %#v\n", ctx.StringMap("notfound"))
err := ctx.Err()
fmt.Println("error:", err)
return err
},
}

_ = app.Run(os.Args)
Expand Down Expand Up @@ -2711,8 +2717,9 @@ func TestWhenExitSubCommandWithCodeThenAppQuitUnexpectedly(t *testing.T) {
}

func newTestApp() *App {
a := NewApp()
a.Writer = io.Discard
a := &App{
Writer: io.Discard,
}
return a
}

Expand Down
7 changes: 1 addition & 6 deletions godoc-current.txt
Original file line number Diff line number Diff line change
Expand Up @@ -333,12 +333,7 @@ type App struct {

// Has unexported fields.
}
App is the main structure of a cli application. It is recommended that an
app be created with the cli.NewApp() function

func NewApp() *App
NewApp creates a new cli Application with some reasonable defaults for Name,
Usage, Version and Action.
App is the main structure of a cli application.

func (a *App) Command(name string) *Command
Command returns the named command on App. Returns nil if the command does
Expand Down
52 changes: 0 additions & 52 deletions help_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -574,58 +574,6 @@ func TestShowCommandHelp_CommandAliases(t *testing.T) {
}
}

func TestHelpNameConsistency(t *testing.T) {
// Setup some very basic templates based on actual AppHelp, CommandHelp
// and SubcommandHelp templates to display the help name
// The inconsistency shows up when users use NewApp() as opposed to
// using App{...} directly
SubcommandHelpTemplate = `{{.HelpName}}`
app := NewApp()
app.Name = "bar"
app.CustomAppHelpTemplate = `{{.HelpName}}`
app.Commands = []*Command{
{
Name: "command1",
CustomHelpTemplate: `{{.HelpName}}`,
Commands: []*Command{
{
Name: "subcommand1",
CustomHelpTemplate: `{{.HelpName}}`,
},
},
},
}

tests := []struct {
name string
args []string
}{
{
name: "App help",
args: []string{"foo"},
},
{
name: "Command help",
args: []string{"foo", "command1"},
},
{
name: "Subcommand help",
args: []string{"foo", "command1", "subcommand1"},
},
}

for _, tt := range tests {
output := &bytes.Buffer{}
app.Writer = output
if err := app.Run(tt.args); err != nil {
t.Error(err)
}
if !strings.Contains(output.String(), "bar") {
t.Errorf("expected output to contain bar; got: %q", output.String())
}
}
}

func TestShowSubcommandHelp_CommandAliases(t *testing.T) {
app := &App{
Commands: []*Command{
Expand Down
7 changes: 1 addition & 6 deletions testdata/godoc-v3.x.txt
Original file line number Diff line number Diff line change
Expand Up @@ -333,12 +333,7 @@ type App struct {

// Has unexported fields.
}
App is the main structure of a cli application. It is recommended that an
app be created with the cli.NewApp() function

func NewApp() *App
NewApp creates a new cli Application with some reasonable defaults for Name,
Usage, Version and Action.
App is the main structure of a cli application.

func (a *App) Command(name string) *Command
Command returns the named command on App. Returns nil if the command does
Expand Down

0 comments on commit 7919d3a

Please sign in to comment.