Skip to content

Commit 69e3949

Browse files
committed
improves documentation; adds example of non-zero enum default and flag option values; fixes #1
1 parent 0f4ef41 commit 69e3949

File tree

4 files changed

+163
-3
lines changed

4 files changed

+163
-3
lines changed

README.md

Lines changed: 106 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,14 @@ But if you instead want to handle one-of-a-set flags as properly typed
3838
enumerations instead of strings, or if you need (multiple-of-a-set) slice
3939
support, then please read on.
4040

41-
## How To Use: Properly Typed Enum Flag
41+
## How To Use
42+
43+
- [start with your own enum types](#start-with-your-own-enum-types),
44+
- [use existing enum types and non-zero defaults](#use-existing-enum-types),
45+
- [CLI flag with default](#cli-flag-with-default),
46+
- [slice of enums](#slice-of-enums).
47+
48+
### Start With Your Own Enum Types
4249

4350
Without further ado, here's how to define and use enum flags in your own
4451
applications...
@@ -69,7 +76,8 @@ var FooModeIds = map[FooMode][]string{
6976
Bar: {"bar"},
7077
}
7178

72-
// ④ Now use the FooMode enum flag.
79+
// ④ Now use the FooMode enum flag. If you want a non-zero default, then simply
80+
// set it here, such as in "foomode = Bar".
7381
var foomode FooMode
7482

7583
func main() {
@@ -98,9 +106,104 @@ The boilerplate pattern is always the same:
98106
3. Define the mapping of the constants onto enum values (textual
99107
representations).
100108
4. Somewhere, declare a flag variable of your enum flag type.
109+
- If you want to use a non-zero default enum value, just go ahead and set
110+
it: `var foomode = Bar`. It will be used correctly.
101111
5. Wire up your flag variable to its flag long and short names, et cetera.
102112

103-
## How To Use: Slice of Enums
113+
### Use Existing Enum Types
114+
115+
A typical example might be your application using a 3rd party logging package
116+
and you want to offer a `-v` log level CLI flag. Here, we use the existing 3rd
117+
party enum values and set a non-zero default for our logging CLI flag.
118+
119+
Considering the boiler plate shown above, we can now leave out steps ① and ②,
120+
because these definitions come from a 3rd party package. We only need to
121+
supply the textual enum names as ③.
122+
123+
```go
124+
import (
125+
"fmt"
126+
"os"
127+
128+
log "github.com/sirupsen/logrus"
129+
"github.com/spf13/cobra"
130+
"github.com/thediveo/enumflag"
131+
)
132+
133+
func main() {
134+
// ①+② skip "define your own enum flag type" and enumeration values, as we
135+
// already have a 3rd party one.
136+
137+
// ③ Map 3rd party enumeration values to their textual representations
138+
var LoglevelIds = map[log.Level][]string{
139+
log.TraceLevel: {"trace"},
140+
log.DebugLevel: {"debug"},
141+
log.InfoLevel: {"info"},
142+
log.WarnLevel: {"warning", "warn"},
143+
log.ErrorLevel: {"error"},
144+
log.FatalLevel: {"fatal"},
145+
log.PanicLevel: {"panic"},
146+
}
147+
148+
// ④ Define your enum flag value and set the your logging default value.
149+
var loglevel log.Level = log.WarnLevel
150+
151+
rootCmd := &cobra.Command{
152+
Run: func(cmd *cobra.Command, _ []string) {
153+
fmt.Printf("logging level is: %d=%q\n",
154+
loglevel,
155+
cmd.PersistentFlags().Lookup("log").Value.String())
156+
},
157+
}
158+
159+
// ⑤ Define the CLI flag parameters for your wrapped enum flag.
160+
rootCmd.PersistentFlags().Var(
161+
enumflag.New(&loglevel, "log", LoglevelIds, enumflag.EnumCaseInsensitive),
162+
"log",
163+
"sets logging level; can be 'trace', 'debug', 'info', 'warn', 'error', 'fatal', 'panic'")
164+
165+
// Defaults to what we set above: warn level.
166+
_ = rootCmd.Execute()
167+
168+
// User specifies a specific level, such as log level.
169+
rootCmd.SetArgs([]string{"--log", "debug"})
170+
_ = rootCmd.Execute()
171+
}
172+
```
173+
174+
### CLI Flag With Default
175+
176+
Sometimes you might want a CLI enum flag to have a default value when the user
177+
specifies the CLI flag, but not its value. A good example is the `--color`
178+
flag of the `ls` command:
179+
180+
- if just specified as `--color` without a value, it
181+
will default to the value of `auto`;
182+
- otherwise, as specific value can be given, such as
183+
- `--color=always`,
184+
- `--color=never`,
185+
- or even `--color=auto`.
186+
187+
In such situations, use spf13/pflags's
188+
[`NoOptDefVal`](https://godoc.org/github.com/spf13/pflag#Flag) to set the
189+
flag's default value *as text*, if the flag is on the command line without any
190+
options.
191+
192+
The gist here is as follows, please see also
193+
[colormode.go](https://github.com/TheDiveO/lxkns/blob/master/cmd/internal/pkg/style/colormode.go)
194+
from my [lxkns](https://github.com/TheDiveO/lxkns) Linux namespaces discovery
195+
project:
196+
197+
```go
198+
rootCmd.PersistentFlags().VarP(
199+
enumflag.New(&colorize, "color", colorModeIds, enumflag.EnumCaseSensitive),
200+
"color", "c",
201+
"colorize the output; can be 'always' (default if omitted), 'auto',\n"+
202+
"or 'never'")
203+
rootCmd.PersistentFlags().Lookup("color").NoOptDefVal = "always"
204+
```
205+
206+
### Slice of Enums
104207

105208
For a slice of enumerations, simply declare your variable to be a slice of your
106209
enumeration type and then use `enumflag.NewSlice(...)` instead of

example_external_test.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package enumflag_test
2+
3+
import (
4+
"fmt"
5+
"os"
6+
7+
log "github.com/sirupsen/logrus"
8+
"github.com/spf13/cobra"
9+
"github.com/thediveo/enumflag"
10+
)
11+
12+
func init() {
13+
log.SetOutput(os.Stdout)
14+
}
15+
16+
func Example_external() {
17+
// ①+② skip "define your own enum flag type" and enumeration values, as we
18+
// already have a 3rd party one.
19+
20+
// ③ Map 3rd party enumeration values to their textual representations
21+
var LoglevelIds = map[log.Level][]string{
22+
log.TraceLevel: {"trace"},
23+
log.DebugLevel: {"debug"},
24+
log.InfoLevel: {"info"},
25+
log.WarnLevel: {"warning", "warn"},
26+
log.ErrorLevel: {"error"},
27+
log.FatalLevel: {"fatal"},
28+
log.PanicLevel: {"panic"},
29+
}
30+
31+
// ④ Define your enum flag value and set the your logging default value.
32+
var loglevel log.Level = log.WarnLevel
33+
34+
rootCmd := &cobra.Command{
35+
Run: func(cmd *cobra.Command, _ []string) {
36+
fmt.Printf("logging level is: %d=%q\n",
37+
loglevel,
38+
cmd.PersistentFlags().Lookup("log").Value.String())
39+
},
40+
}
41+
42+
// ⑤ Define the CLI flag parameters for your wrapped enum flag.
43+
rootCmd.PersistentFlags().Var(
44+
enumflag.New(&loglevel, "log", LoglevelIds, enumflag.EnumCaseInsensitive),
45+
"log",
46+
"sets logging level; can be 'trace', 'debug', 'info', 'warn', 'error', 'fatal', 'panic'")
47+
48+
_ = rootCmd.Execute()
49+
rootCmd.SetArgs([]string{"--log", "debug"})
50+
_ = rootCmd.Execute()
51+
// Output:
52+
// logging level is: 3="warning"
53+
// logging level is: 5="debug"
54+
}

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ go 1.13
55
require (
66
github.com/onsi/ginkgo v1.12.0
77
github.com/onsi/gomega v1.9.0
8+
github.com/sirupsen/logrus v1.2.0
89
github.com/spf13/cobra v0.0.7
910
)

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40T
7676
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
7777
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
7878
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
79+
github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo=
7980
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
8081
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
8182
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
@@ -98,6 +99,7 @@ go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
9899
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
99100
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
100101
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
102+
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
101103
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
102104
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
103105
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=

0 commit comments

Comments
 (0)