enumflag

package module
v0.9.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 11, 2020 License: Apache-2.0 Imports: 4 Imported by: 39

README

CLI Enumeration Flags

GoDoc GitHub build and test Go Report Card Coverage

enumflag is a Golang package which supplements the Golang CLI flag handling packages spf13/cobra and spf13/pflag with enumeration flags.

For instance, users can specify enum flags as --mode=foo or --mode=bar, where foo and bar are valid enumeration values. Other values which are not part of the set of allowed enumeration values cannot be set and raise CLI flag errors.

Application programmers then simply deal with enumeration values in form of uints (or ints), liberated from parsing strings and validating enumeration flags.

How To Use

Without further ado, here's how to define and use enum flags in your own applications...

import (
    "fmt"

    "github.com/spf13/cobra"
    "github.com/thediveo/enumflag"
)

// ① Defines a new enum flag type.
type FooMode enumflag.Flag

// ② Defines the enumeration values for our new FooMode enum flag type.
const (
    Foo FooMode = iota
    Bar
)

// ③ Implements the methods required by spf13/cobra in order to use the enum as
// a flag.
func (f *FooMode) String() string     { return enumflag.String(f) }
func (f *FooMode) Set(s string) error { return enumflag.Set(f, s) }
func (f *FooMode) Type() string       { return "foomode" }

// ④ Implements the method required by enumflag to map enum values to their
// textual identifiers.
func (f *FooMode) Enums() (interface{}, enumflag.EnumCaseSensitivity) {
    return map[FooMode][]string{
        Foo: {"foo"},
        Bar: {"bar"},
    }, enumflag.EnumCaseInsensitive
}

// ⑤ Now use the FooMode enum flag.
var foomode FooMode

func main() {
    rootCmd := &cobra.Command{
        Run: func(_ *cobra.Command, _ []string) {
            fmt.Printf("mode is: %d=%q\n", foomode, foomode.String())
        },
    }
    // ⑥ Define the parameters for our FooMode enum flag.
    rootCmd.PersistentFlags().VarP(
        &foomode,
        "mode", "m",
        "foos the output; can be 'foo' or 'bar'")
    rootCmd.SetArgs([]string{"--mode", "bAr"})
    _ = rootCmd.Execute()
}

Important: always define a separate type for each of your enumeration flag types. Behind the scenes, enumflag caches the enum mappings based on enumeration flag type.

The boilerplate pattern is always the same; unfortunately due to the Golang language design we have to live with this boilerplate.

  1. Define your own new enumeration type, such as type FooMode enumflag.Flag.
  2. Define the constants in your enumeration.
  3. Implement the methods String and Set by routing them into enumflag.String and enumflag.Set respectively. Make sure your Type method returns some sensible and especially unique flag type name.
  4. Implement method Enums to return the enum value to textual representation mapping, as well as the desired case sensitivity.
  5. Somewhere, declare a flag variable of your enum flag type.
  6. Wire up your flag variable to its flag long and short names, et cetera.

lxkns is Copyright 2020 Harald Albrecht, and licensed under the Apache License, Version 2.0.

Documentation

Overview

Package enumflag supplements the Golang CLI flag handling packages spf13/cobra and spf13/pflag with enumeration flags.

For instance, users can specify enum flags as "--mode=foo" or "--mode=bar", where "foo" and "bar" are valid enumeration values. Other values which are not part of the set of allowed enumeration values cannot be set and raise CLI flag errors.

Application programmers then simply deal with enumeration values in form of uints (or ints), liberated from parsing strings and validating enumeration flags.

Example

New enum flag types should be derived from "enumflag.Flag"; however this is not strictly necessary as long as they can be converted into the "enumflag.Flag" type. Actually, "enumflag.Flag" is just a fancy name for an "uint". Enum flag types need to implement pflag's "Value" interface (https://godoc.org/github.com/spf13/pflag#Value), as well as the enumflag's "Mapper" interface. This example shows the boilerplate code, which should be easy to copy, paste, and adapt: simply change the Type()-returned name, and the Enums() returned textual enum representations and case sensitivity.

package main

import (
	"fmt"

	"github.com/spf13/cobra"
	"github.com/thediveo/enumflag"
)

// ① Defines a new enum flag type.
type FooMode enumflag.Flag

// ② Defines the enumeration values for our new FooMode enum flag type.
const (
	Foo FooMode = iota
	Bar
)

// ③ Implements the methods required by spf13/cobra in order to use the enum
// as a flag.
func (f *FooMode) String() string     { return enumflag.String(f) }
func (f *FooMode) Set(s string) error { return enumflag.Set(f, s) }
func (f *FooMode) Type() string       { return "foomode" }

// ④ Implements the method required by enumflag to map enum values to their
// textual identifiers.
func (f *FooMode) Enums() (interface{}, enumflag.EnumCaseSensitivity) {
	return map[FooMode][]string{
		Foo: {"foo"},
		Bar: {"bar"},
	}, enumflag.EnumCaseInsensitive
}

// New enum flag types should be derived from "enumflag.Flag"; however this is
// not strictly necessary as long as they can be converted into the
// "enumflag.Flag" type. Actually, "enumflag.Flag" is just a fancy name for an
// "uint". Enum flag types need to implement pflag's "Value" interface
// (https://godoc.org/github.com/spf13/pflag#Value), as well as the enumflag's
// "Mapper" interface. This example shows the boilerplate code, which should be
// easy to copy, paste, and adapt: simply change the Type()-returned name, and
// the Enums() returned textual enum representations and case sensitivity.
func main() {
	var foomode FooMode // ⑤ Now use the FooMode enum flag.
	rootCmd := &cobra.Command{
		Run: func(_ *cobra.Command, _ []string) {
			fmt.Printf("mode is: %d=%q\n", foomode, foomode.String())
		},
	}
	// ⑥ Define the parameters for our FooMode enum flag.
	rootCmd.PersistentFlags().VarP(
		&foomode,
		"mode", "m",
		"foos the output; can be 'foo' or 'bar'")
	rootCmd.SetArgs([]string{"--mode", "bAr"})
	_ = rootCmd.Execute()
}
Output:

mode is: 1="bar"

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Set

func Set(flag interface{}, s string) error

Set sets an enumeration flag to the value corresponding with the given textual representation. It returns an error if the textual representation doesn't match any registered one for the given enumeration flag.

func String

func String(flag interface{}) string

String returns the textual representation of an enumeration (flag) value. In case multiple textual representations (identifiers) exist for the same enumeration value, then only the first one is returned, which is considered to be the canonical textual representation.

Types

type EnumCaseSensitivity

type EnumCaseSensitivity bool

EnumCaseSensitivity specifies whether the textual representations of enum values are considered to be case sensitive, or not.

const (
	EnumCaseInsensitive EnumCaseSensitivity = false // case insensitive textual representations
	EnumCaseSensitive   EnumCaseSensitivity = true  // case sensitive textual representations
)

Controls whether the textual representations for enum values are case sensitive, or not. If they are case insensitive, then the textual representation must be registered in lower case.

type EnumIdentifiers

type EnumIdentifiers map[Flag][]string

EnumIdentifiers maps enumeration values to their corresponding textual representations. This mapping is a one-to-many mapping in that the same enumeration value may have more than only one associated textual representation.

type Flag

type Flag uint

Flag represents a CLI (enumeration) flag which can take on only a single enumeration value out of a fixed set of enumeration values. Applications using the enumflag package might want to derive their enumeration flags from Flag, such as "type MyFoo enumflag.Flag"

type Mapper

type Mapper interface {
	Enums() (interface{}, EnumCaseSensitivity)
}

Mapper returns the mapping between enumeration values and their corresponding textual representations. If multiple textual representations exist for the same enumeration value, then the first textual representation is considered to be canonical and the one returned by String() when applied on an enumeration flag. Enumeration flags must implement this interface in order to be managed by the enumflag package.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL