Desertbit/grumble: Difference between revisions
(Created page with "=External= * https://github.com/desertbit/grumble =Internal= * Go Open Source Packages =Overview= =Unit Testing Commands= ==Option 1== <syntaxhighlight lang='go'> command := somepackage.SomeCommand(...) app := grumble.New(&grumble.Config{Name: "test"}) app.AddCommand(command) args := []string{ "somecommand", "--arg1", "test1", "--arg2", "test2", } err := app.RunCommand(args) </syntaxhighlight> ==Option 2== <syntaxhighl...") |
|||
(21 intermediate revisions by the same user not shown) | |||
Line 4: | Line 4: | ||
* [[Go_Open_Source_Packages#Overview|Go Open Source Packages]] | * [[Go_Open_Source_Packages#Overview|Go Open Source Packages]] | ||
=Overview= | =Overview= | ||
=Concepts= | |||
==Context== | |||
<code>grumble.Context</code> is passed to a command's <code>Run</code> function as argument. The context contains the values for flags and arguments for one command run instance, and it passed to a [[#Command|command]]'s <code>Run</code> function. | |||
==Flags== | |||
===Flag Types=== | |||
==Arguments== | |||
The arguments that don't have a <code>grumble.Default()</code> <code>ArgOption</code> are mandatory and must be specified on command line. | |||
Mandatory arguments not allowed after the optional ones. | |||
===Argument Types=== | |||
==Command== | |||
The values for the flags and arguments come via the <code>[[#Context|Context]]</code> instance passed to the command's <code>Run</code> function (<code>func(c *grumble.Context) error</code>). | |||
=Programming Model= | |||
==Define an <tt>app</tt>== | |||
<syntaxhighlight lang='go'> | |||
app := grumble.New(&grumble.Config{ | |||
Name: "someapp", | |||
Description: "A grumble app", | |||
HistoryFile: "/tmp/someapp.history", | |||
Prompt: "smapp> ", | |||
PromptColor: color.New(color.FgBlue, color.Bold), | |||
HelpHeadlineColor: color.New(color.FgBlack, color.Bold), | |||
HelpHeadlineUnderline: true, | |||
HelpSubCommands: true, | |||
Flags: func(f *grumble.Flags) { | |||
// App-level flags | |||
}, | |||
}) | |||
</syntaxhighlight> | |||
<font color=darkkhaki>TODO: more about app-level flags.</font> | |||
==Define a Number of Commands== | |||
<syntaxhighlight lang='go'> | |||
gc := &grumble.Command{ | |||
Name: "create", | |||
Help: "creates a widget.", | |||
LongHelp: "creates a widget with the specified color, size. The widget is disabled by default.", | |||
Aliases: []string{"c"}, | |||
Flags: func(f *grumble.Flags) { | |||
f.String("c", "color", "blue", "A color") | |||
f.Int("s", "size", 10, "A size") | |||
f.Bool("e", "enabled", false, "Whether is enabled or disabled by default") | |||
}, | |||
Args: func(a *grumble.Args) { | |||
a.String("arg1", "First string arg") // no Default, mandatory argument | |||
a.Int("arg2", "Second int arg", grumble.Default(20)) | |||
a.Bool("arg3", "Third bool arg", grumble.Default(true)) | |||
}, | |||
Run: func(c *grumble.Context) error { | |||
clr := c.Flags.String("color") | |||
size := c.Flags.Int("size") | |||
enabled := c.Flags.Bool("enabled") | |||
arg1 := c.Args.String("arg1") | |||
arg2 := c.Args.Int("arg2") | |||
arg3 := c.Args.Bool("arg3") | |||
_, err := c.App.Printf("creating a %s widget of size %d, enabled: %t [%v, %v, %v] ...\n", clr, size, enabled, arg1, arg2, arg3) | |||
if err != nil { | |||
return err | |||
} | |||
return nil | |||
}, | |||
} | |||
</syntaxhighlight> | |||
==Add Commands to <tt>app</tt>== | |||
<syntaxhighlight lang='go'> | |||
app.AddCommand(gc) | |||
</syntaxhighlight> | |||
==Run the <tt>app</tt>== | |||
To handle the errors by yourself: | |||
<syntaxhighlight lang='go'> | |||
err := app.Run() | |||
</syntaxhighlight> | |||
To have the errors handled for you: | |||
<syntaxhighlight lang='go'> | |||
grumble.Main(app) | |||
</syntaxhighlight> | |||
==Run an Individual Command Programmatically== | |||
<syntaxhighlight lang='go'> | |||
app.RunCommand([]string{"somecommand", "--someflag", "some value")}) | |||
</syntaxhighlight> | |||
=Unit Testing Commands= | =Unit Testing Commands= | ||
These options do not capture the command output, just side effects: | |||
==Option 1== | ==Option 1== | ||
Line 21: | Line 115: | ||
==Option 2== | ==Option 2== | ||
In this case, a flag '''must''' be registered, even if it has a zero value, otherwise the attempt to get the flag will panic the runtime. | |||
<syntaxhighlight lang='go'> | <syntaxhighlight lang='go'> | ||
flags := map[string]*grumble.FlagMapItem{ | flags := map[string]*grumble.FlagMapItem{ | ||
"arg1": | "arg1": return &grumble.FlagMapItem{Value: arg1}, | ||
"arg2": | "arg2": return &grumble.FlagMapItem{Value: arg2}, | ||
} | } | ||
ctx := &grumble.Context{ | ctx := &grumble.Context{ | ||
Line 34: | Line 130: | ||
err := command.Run(ctx) | err := command.Run(ctx) | ||
</syntaxhighlight> | </syntaxhighlight> | ||
==Option 3== | |||
The test fixture added to the devicecompute repository. | |||
==Capture and Test Output== |
Latest revision as of 05:32, 23 November 2024
External
Internal
Overview
Concepts
Context
grumble.Context
is passed to a command's Run
function as argument. The context contains the values for flags and arguments for one command run instance, and it passed to a command's Run
function.
Flags
Flag Types
Arguments
The arguments that don't have a grumble.Default()
ArgOption
are mandatory and must be specified on command line.
Mandatory arguments not allowed after the optional ones.
Argument Types
Command
The values for the flags and arguments come via the Context
instance passed to the command's Run
function (func(c *grumble.Context) error
).
Programming Model
Define an app
app := grumble.New(&grumble.Config{
Name: "someapp",
Description: "A grumble app",
HistoryFile: "/tmp/someapp.history",
Prompt: "smapp> ",
PromptColor: color.New(color.FgBlue, color.Bold),
HelpHeadlineColor: color.New(color.FgBlack, color.Bold),
HelpHeadlineUnderline: true,
HelpSubCommands: true,
Flags: func(f *grumble.Flags) {
// App-level flags
},
})
TODO: more about app-level flags.
Define a Number of Commands
gc := &grumble.Command{
Name: "create",
Help: "creates a widget.",
LongHelp: "creates a widget with the specified color, size. The widget is disabled by default.",
Aliases: []string{"c"},
Flags: func(f *grumble.Flags) {
f.String("c", "color", "blue", "A color")
f.Int("s", "size", 10, "A size")
f.Bool("e", "enabled", false, "Whether is enabled or disabled by default")
},
Args: func(a *grumble.Args) {
a.String("arg1", "First string arg") // no Default, mandatory argument
a.Int("arg2", "Second int arg", grumble.Default(20))
a.Bool("arg3", "Third bool arg", grumble.Default(true))
},
Run: func(c *grumble.Context) error {
clr := c.Flags.String("color")
size := c.Flags.Int("size")
enabled := c.Flags.Bool("enabled")
arg1 := c.Args.String("arg1")
arg2 := c.Args.Int("arg2")
arg3 := c.Args.Bool("arg3")
_, err := c.App.Printf("creating a %s widget of size %d, enabled: %t [%v, %v, %v] ...\n", clr, size, enabled, arg1, arg2, arg3)
if err != nil {
return err
}
return nil
},
}
Add Commands to app
app.AddCommand(gc)
Run the app
To handle the errors by yourself:
err := app.Run()
To have the errors handled for you:
grumble.Main(app)
Run an Individual Command Programmatically
app.RunCommand([]string{"somecommand", "--someflag", "some value")})
Unit Testing Commands
These options do not capture the command output, just side effects:
Option 1
command := somepackage.SomeCommand(...)
app := grumble.New(&grumble.Config{Name: "test"})
app.AddCommand(command)
args := []string{
"somecommand",
"--arg1", "test1",
"--arg2", "test2",
}
err := app.RunCommand(args)
Option 2
In this case, a flag must be registered, even if it has a zero value, otherwise the attempt to get the flag will panic the runtime.
flags := map[string]*grumble.FlagMapItem{
"arg1": return &grumble.FlagMapItem{Value: arg1},
"arg2": return &grumble.FlagMapItem{Value: arg2},
}
ctx := &grumble.Context{
Flags: flags,
Context: context.Background(),
}
command := somepackage.SomeCommand(...)
err := command.Run(ctx)
Option 3
The test fixture added to the devicecompute repository.